Skip to content

Commit 3842d4e

Browse files
committed
fix: guard arity and format jaccard results
1 parent 775c48f commit 3842d4e

File tree

2 files changed

+272
-2
lines changed

2 files changed

+272
-2
lines changed

src/r_32.c

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include "r_32.h"
2+
#include <limits.h>
3+
#include <stdio.h>
24
#include "rmalloc.h"
35
#include "roaring.h"
46
#include "common.h"
@@ -19,6 +21,53 @@ Bitmap* BITMAP_NILL = NULL;
1921
return REDISMODULE_ERR; \
2022
} while(0)
2123

24+
static int ReplyWithJaccardRatio(RedisModuleCtx* ctx, uint64_t intersection, uint64_t union_count) {
25+
if (union_count == 0) {
26+
return RedisModule_ReplyWithStringBuffer(ctx, "-1", 2);
27+
}
28+
29+
if (intersection == 0) {
30+
return RedisModule_ReplyWithStringBuffer(ctx, "0", 1);
31+
}
32+
33+
if (intersection == union_count) {
34+
return RedisModule_ReplyWithStringBuffer(ctx, "1", 1);
35+
}
36+
37+
static const uint64_t pow10[] = {
38+
1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, 1000000000ULL
39+
};
40+
41+
uint64_t scaled = intersection;
42+
for (int scale = 1; scale < (int) (sizeof(pow10) / sizeof(pow10[0])); scale++) {
43+
if (scaled > UINT64_MAX / 10) {
44+
break;
45+
}
46+
47+
scaled *= 10;
48+
49+
if (scaled % union_count == 0) {
50+
uint64_t value = scaled / union_count;
51+
uint64_t int_part = value / pow10[scale];
52+
uint64_t frac_part = value % pow10[scale];
53+
char buffer[32];
54+
int len = snprintf(
55+
buffer,
56+
sizeof(buffer),
57+
"%llu.%0*llu",
58+
(unsigned long long) int_part,
59+
scale,
60+
(unsigned long long) frac_part);
61+
return RedisModule_ReplyWithStringBuffer(ctx, buffer, (size_t) len);
62+
}
63+
}
64+
65+
double result = (double) intersection / (double) union_count;
66+
char buffer[32];
67+
int len = snprintf(buffer, sizeof(buffer), "%.17g", result);
68+
return RedisModule_ReplyWithStringBuffer(ctx, buffer, (size_t) len);
69+
}
70+
2271
static int GetBitmapKey(RedisModuleCtx* ctx, RedisModuleString* keyName, Bitmap** value_out, int mode) {
2372
RedisModuleKey* key = RedisModule_OpenKey(ctx, keyName, mode);
2473
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) {
@@ -103,6 +152,10 @@ void BitmapFree(void* value) {
103152
* R.SETFULL <key>
104153
* */
105154
int RSetFullCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
155+
if (argc != 2) {
156+
return RedisModule_WrongArity(ctx);
157+
}
158+
106159
RedisModule_AutoMemory(ctx);
107160
RedisModuleKey* key;
108161
Bitmap* bitmap;
@@ -127,6 +180,10 @@ int RSetFullCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
127180
* R.SETRANGE <key> <start_num> <end_num>
128181
* */
129182
int RSetRangeCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
183+
if (argc != 4) {
184+
return RedisModule_WrongArity(ctx);
185+
}
186+
130187
RedisModule_AutoMemory(ctx);
131188
RedisModuleKey* key;
132189
Bitmap* bitmap;
@@ -226,6 +283,10 @@ int RGetBitCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
226283
* R.GETBITS <key> offset [offset1 offset2 ... offsetN]
227284
* */
228285
int RGetBitManyCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
286+
if (argc < 3) {
287+
return RedisModule_WrongArity(ctx);
288+
}
289+
229290
RedisModule_AutoMemory(ctx);
230291
RedisModuleKey* key;
231292
Bitmap* bitmap;
@@ -270,6 +331,10 @@ int RGetBitManyCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc)
270331
* R.CLEARBITS <key> offset [offset1 offset2 ... offsetN] [COUNT]
271332
* */
272333
int RClearBitsCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
334+
if (argc < 3) {
335+
return RedisModule_WrongArity(ctx);
336+
}
337+
273338
RedisModule_AutoMemory(ctx);
274339
RedisModuleKey* key;
275340
Bitmap* bitmap;
@@ -318,6 +383,10 @@ int RClearBitsCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
318383
* R.OPTIMIZE <key> [MEM]
319384
* */
320385
int ROptimizeBitCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
386+
if (argc < 2 || argc > 3) {
387+
return RedisModule_WrongArity(ctx);
388+
}
389+
321390
RedisModule_AutoMemory(ctx);
322391
Bitmap* bitmap;
323392

@@ -348,6 +417,10 @@ int ROptimizeBitCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc)
348417
* R.SETINTARRAY <key> <value1> [<value2> <value3> ... <valueN>]
349418
* */
350419
int RSetIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
420+
if (argc < 3) {
421+
return RedisModule_WrongArity(ctx);
422+
}
423+
351424
RedisModule_AutoMemory(ctx);
352425
RedisModuleKey* key;
353426
Bitmap* bitmap;
@@ -381,6 +454,10 @@ int RSetIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc)
381454
* R.DIFF <dest> <decreasing> <deductible>
382455
* */
383456
int RDiffCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
457+
if (argc != 4) {
458+
return RedisModule_WrongArity(ctx);
459+
}
460+
384461
RedisModule_AutoMemory(ctx);
385462
RedisModuleKey* key;
386463
Bitmap* bitmap;
@@ -418,6 +495,10 @@ int RDiffCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
418495
* R.APPENDINTARRAY <key> <value1> [<value2> <value3> ... <valueN>]
419496
* */
420497
int RAppendIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
498+
if (argc < 3) {
499+
return RedisModule_WrongArity(ctx);
500+
}
501+
421502
RedisModule_AutoMemory(ctx);
422503
RedisModuleKey* key;
423504
Bitmap* bitmap;
@@ -457,6 +538,10 @@ int RAppendIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int ar
457538
* R.DELETEINTARRAY <key> <value1> [<value2> <value3> ... <valueN>]
458539
* */
459540
int RDeleteIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
541+
if (argc < 3) {
542+
return RedisModule_WrongArity(ctx);
543+
}
544+
460545
RedisModule_AutoMemory(ctx);
461546
RedisModuleKey* key;
462547
Bitmap* bitmap;
@@ -493,6 +578,10 @@ int RDeleteIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int ar
493578
* R.RANGEINTARRAY <key> <start> <end>
494579
* */
495580
int RRangeIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
581+
if (argc != 4) {
582+
return RedisModule_WrongArity(ctx);
583+
}
584+
496585
RedisModule_AutoMemory(ctx);
497586
RedisModuleKey* key;
498587
Bitmap* bitmap;
@@ -548,6 +637,10 @@ int RRangeIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int arg
548637
* R.GETINTARRAY <key>
549638
* */
550639
int RGetIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
640+
if (argc != 2) {
641+
return RedisModule_WrongArity(ctx);
642+
}
643+
551644
RedisModule_AutoMemory(ctx);
552645
RedisModuleKey* key;
553646
Bitmap* bitmap;
@@ -579,6 +672,10 @@ int RGetIntArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc)
579672
* R.SETBITARRAY <key> <value1>
580673
* */
581674
int RSetBitArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
675+
if (argc != 3) {
676+
return RedisModule_WrongArity(ctx);
677+
}
678+
582679
RedisModule_AutoMemory(ctx);
583680
RedisModuleKey* key;
584681
Bitmap* bitmap;
@@ -604,6 +701,10 @@ int RSetBitArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc)
604701
* R.GETBITARRAY <key>
605702
* */
606703
int RGetBitArrayCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
704+
if (argc != 2) {
705+
return RedisModule_WrongArity(ctx);
706+
}
707+
607708
RedisModule_AutoMemory(ctx);
608709
RedisModuleKey* key;
609710
Bitmap* bitmap;
@@ -763,6 +864,10 @@ int RBitFlip(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
763864
* R.BITOP <operation> <destkey> <key> [<key> ...]
764865
* */
765866
int RBitOpCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
867+
if (argc < 4) {
868+
return RedisModule_WrongArity(ctx);
869+
}
870+
766871
RedisModule_AutoMemory(ctx);
767872
size_t len;
768873
const char* operation = RedisModule_StringPtrLen(argv[1], &len);
@@ -798,6 +903,10 @@ int RBitOpCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
798903
* R.BITCOUNT <key>
799904
* */
800905
int RBitCountCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
906+
if (argc != 2) {
907+
return RedisModule_WrongArity(ctx);
908+
}
909+
801910
RedisModule_AutoMemory(ctx);
802911
RedisModuleKey* key;
803912
Bitmap* bitmap;
@@ -820,6 +929,10 @@ int RBitCountCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
820929
* R.BITPOS <key> <bit>
821930
* */
822931
int RBitPosCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
932+
if (argc != 3) {
933+
return RedisModule_WrongArity(ctx);
934+
}
935+
823936
RedisModule_AutoMemory(ctx);
824937
RedisModuleKey* key;
825938
Bitmap* bitmap;
@@ -847,6 +960,10 @@ int RBitPosCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
847960
* R.MIN <key>
848961
* */
849962
int RMinCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
963+
if (argc != 2) {
964+
return RedisModule_WrongArity(ctx);
965+
}
966+
850967
RedisModule_AutoMemory(ctx);
851968
RedisModuleKey* key;
852969
Bitmap* bitmap;
@@ -868,6 +985,10 @@ int RMinCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
868985
* R.MAX <key>
869986
* */
870987
int RMaxCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
988+
if (argc != 2) {
989+
return RedisModule_WrongArity(ctx);
990+
}
991+
871992
RedisModule_AutoMemory(ctx);
872993
RedisModuleKey* key;
873994
Bitmap* bitmap;
@@ -889,6 +1010,10 @@ int RMaxCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
8891010
* R.CLEAR <key>
8901011
* */
8911012
int RClearCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
1013+
if (argc != 2) {
1014+
return RedisModule_WrongArity(ctx);
1015+
}
1016+
8921017
RedisModule_AutoMemory(ctx);
8931018
RedisModuleKey* key;
8941019
Bitmap* bitmap;
@@ -915,6 +1040,10 @@ int RClearCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
9151040
* R.CONTAINS <key1> <key2> [ALL, ALL_STRICT]
9161041
* */
9171042
int RContainsCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
1043+
if (argc != 3 && argc != 4) {
1044+
return RedisModule_WrongArity(ctx);
1045+
}
1046+
9181047
RedisModule_AutoMemory(ctx);
9191048
Bitmap* b1;
9201049
Bitmap* b2;
@@ -954,6 +1083,10 @@ int RContainsCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
9541083
* R.JACCARD <key1> <key2>
9551084
* */
9561085
int RJaccardCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
1086+
if (argc != 3) {
1087+
return RedisModule_WrongArity(ctx);
1088+
}
1089+
9571090
RedisModule_AutoMemory(ctx);
9581091
Bitmap* b1;
9591092
Bitmap* b2;
@@ -966,7 +1099,9 @@ int RJaccardCommand(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) {
9661099
return REDISMODULE_ERR;
9671100
}
9681101

969-
return RedisModule_ReplyWithDouble(ctx, bitmap_jaccard(b1, b2));
1102+
uint64_t intersection = roaring_bitmap_and_cardinality(b1, b2);
1103+
uint64_t union_count = roaring_bitmap_or_cardinality(b1, b2);
1104+
return ReplyWithJaccardRatio(ctx, intersection, union_count);
9701105
}
9711106

9721107
void R32Module_onShutdown(RedisModuleCtx* ctx, RedisModuleEvent e, uint64_t sub, void* data) {

0 commit comments

Comments
 (0)