Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
bbdbfabf
Unverified
Commit
bbdbfabf
authored
Nov 04, 2019
by
Salvatore Sanfilippo
Committed by
GitHub
Nov 04, 2019
Browse files
Merge pull request #6531 from oranagra/rm_save_long_double
Module API for loading and saving long double
parents
720d1fd3
779aebc9
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
bbdbfabf
...
...
@@ -3769,6 +3769,31 @@ loaderr:
return
0
;
}
/* In the context of the rdb_save method of a module data type, saves a long double
* value to the RDB file. The double can be a valid number, a NaN or infinity.
* It is possible to load back the value with RedisModule_LoadLongDouble(). */
void
RM_SaveLongDouble
(
RedisModuleIO
*
io
,
long
double
value
)
{
if
(
io
->
error
)
return
;
char
buf
[
MAX_LONG_DOUBLE_CHARS
];
/* Long double has different number of bits in different platforms, so we
* save it as a string type. */
size_t
len
=
ld2string
(
buf
,
sizeof
(
buf
),
value
,
LD_STR_HEX
);
RM_SaveStringBuffer
(
io
,
buf
,
len
+
1
);
/* len+1 for '\0' */
}
/* In the context of the rdb_save method of a module data type, loads back the
* long double value saved by RedisModule_SaveLongDouble(). */
long
double
RM_LoadLongDouble
(
RedisModuleIO
*
io
)
{
if
(
io
->
error
)
return
0
;
long
double
value
;
size_t
len
;
char
*
str
=
RM_LoadStringBuffer
(
io
,
&
len
);
if
(
!
str
)
return
0
;
string2ld
(
str
,
len
,
&
value
);
RM_Free
(
str
);
return
value
;
}
/* Iterate over modules, and trigger rdb aux saving for the ones modules types
* who asked for it. */
ssize_t
rdbSaveModulesAux
(
rio
*
rdb
,
int
when
)
{
...
...
@@ -6849,6 +6874,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
LoadDouble
);
REGISTER_API
(
SaveFloat
);
REGISTER_API
(
LoadFloat
);
REGISTER_API
(
SaveLongDouble
);
REGISTER_API
(
LoadLongDouble
);
REGISTER_API
(
EmitAOF
);
REGISTER_API
(
Log
);
REGISTER_API
(
LogIOError
);
...
...
src/networking.c
View file @
bbdbfabf
...
...
@@ -530,7 +530,7 @@ void addReplyHumanLongDouble(client *c, long double d) {
decrRefCount
(
o
);
}
else
{
char
buf
[
MAX_LONG_DOUBLE_CHARS
];
int
len
=
ld2string
(
buf
,
sizeof
(
buf
),
d
,
1
);
int
len
=
ld2string
(
buf
,
sizeof
(
buf
),
d
,
LD_STR_HUMAN
);
addReplyProto
(
c
,
","
,
1
);
addReplyProto
(
c
,
buf
,
len
);
addReplyProto
(
c
,
"
\r\n
"
,
2
);
...
...
src/object.c
View file @
bbdbfabf
...
...
@@ -178,7 +178,7 @@ robj *createStringObjectFromLongLongForValue(long long value) {
* The 'humanfriendly' option is used for INCRBYFLOAT and HINCRBYFLOAT. */
robj
*
createStringObjectFromLongDouble
(
long
double
value
,
int
humanfriendly
)
{
char
buf
[
MAX_LONG_DOUBLE_CHARS
];
int
len
=
ld2string
(
buf
,
sizeof
(
buf
),
value
,
humanfriendly
);
int
len
=
ld2string
(
buf
,
sizeof
(
buf
),
value
,
humanfriendly
?
LD_STR_HUMAN
:
LD_STR_AUTO
);
return
createStringObject
(
buf
,
len
);
}
...
...
src/redismodule.h
View file @
bbdbfabf
...
...
@@ -535,6 +535,8 @@ void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double valu
double
REDISMODULE_API_FUNC
(
RedisModule_LoadDouble
)(
RedisModuleIO
*
io
);
void
REDISMODULE_API_FUNC
(
RedisModule_SaveFloat
)(
RedisModuleIO
*
io
,
float
value
);
float
REDISMODULE_API_FUNC
(
RedisModule_LoadFloat
)(
RedisModuleIO
*
io
);
void
REDISMODULE_API_FUNC
(
RedisModule_SaveLongDouble
)(
RedisModuleIO
*
io
,
long
double
value
);
long
double
REDISMODULE_API_FUNC
(
RedisModule_LoadLongDouble
)(
RedisModuleIO
*
io
);
void
REDISMODULE_API_FUNC
(
RedisModule_Log
)(
RedisModuleCtx
*
ctx
,
const
char
*
level
,
const
char
*
fmt
,
...);
void
REDISMODULE_API_FUNC
(
RedisModule_LogIOError
)(
RedisModuleIO
*
io
,
const
char
*
levelstr
,
const
char
*
fmt
,
...);
void
REDISMODULE_API_FUNC
(
RedisModule__Assert
)(
const
char
*
estr
,
const
char
*
file
,
int
line
);
...
...
@@ -741,6 +743,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
LoadDouble
);
REDISMODULE_GET_API
(
SaveFloat
);
REDISMODULE_GET_API
(
LoadFloat
);
REDISMODULE_GET_API
(
SaveLongDouble
);
REDISMODULE_GET_API
(
LoadLongDouble
);
REDISMODULE_GET_API
(
EmitAOF
);
REDISMODULE_GET_API
(
Log
);
REDISMODULE_GET_API
(
LogIOError
);
...
...
src/t_hash.c
View file @
bbdbfabf
...
...
@@ -621,7 +621,7 @@ void hincrbyfloatCommand(client *c) {
}
char
buf
[
MAX_LONG_DOUBLE_CHARS
];
int
len
=
ld2string
(
buf
,
sizeof
(
buf
),
value
,
1
);
int
len
=
ld2string
(
buf
,
sizeof
(
buf
),
value
,
LD_STR_HUMAN
);
new
=
sdsnewlen
(
buf
,
len
);
hashTypeSet
(
o
,
c
->
argv
[
2
]
->
ptr
,
new
,
HASH_SET_TAKE_VALUE
);
addReplyBulkCBuffer
(
c
,
buf
,
len
);
...
...
src/util.c
View file @
bbdbfabf
...
...
@@ -510,15 +510,17 @@ int d2string(char *buf, size_t len, double value) {
return
len
;
}
/* Convert a long double into a string. If humanfriendly is non-zero
* it does not use exponential format and trims trailing zeroes at the end,
* however this results in loss of precision. Otherwise exp format is used
* and the output of snprintf() is not modified.
/* Create a string object from a long double.
* If mode is humanfriendly it does not use exponential format and trims trailing
* zeroes at the end (may result in loss of precision).
* If mode is default exp format is used and the output of snprintf()
* is not modified (may result in loss of precision).
* If mode is hex hexadecimal format is used (no loss of precision)
*
* The function returns the length of the string or zero if there was not
* enough buffer room to store it. */
int
ld2string
(
char
*
buf
,
size_t
len
,
long
double
value
,
int
humanfriendly
)
{
size_t
l
;
int
ld2string
(
char
*
buf
,
size_t
len
,
long
double
value
,
ld2string_mode
mode
)
{
size_t
l
=
0
;
if
(
isinf
(
value
))
{
/* Libc in odd systems (Hi Solaris!) will format infinite in a
...
...
@@ -531,26 +533,36 @@ int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
memcpy
(
buf
,
"-inf"
,
4
);
l
=
4
;
}
}
else
if
(
humanfriendly
)
{
/* We use 17 digits precision since with 128 bit floats that precision
* after rounding is able to represent most small decimal numbers in a
* way that is "non surprising" for the user (that is, most small
* decimal numbers will be represented in a way that when converted
* back into a string are exactly the same as what the user typed.) */
l
=
snprintf
(
buf
,
len
,
"%.17Lf"
,
value
);
if
(
l
+
1
>
len
)
return
0
;
/* No room. */
/* Now remove trailing zeroes after the '.' */
if
(
strchr
(
buf
,
'.'
)
!=
NULL
)
{
char
*
p
=
buf
+
l
-
1
;
while
(
*
p
==
'0'
)
{
p
--
;
l
--
;
}
else
{
switch
(
mode
)
{
case
LD_STR_AUTO
:
l
=
snprintf
(
buf
,
len
,
"%.17Lg"
,
value
);
if
(
l
+
1
>
len
)
return
0
;
/* No room. */
break
;
case
LD_STR_HEX
:
l
=
snprintf
(
buf
,
len
,
"%La"
,
value
);
if
(
l
+
1
>
len
)
return
0
;
/* No room. */
break
;
case
LD_STR_HUMAN
:
/* We use 17 digits precision since with 128 bit floats that precision
* after rounding is able to represent most small decimal numbers in a
* way that is "non surprising" for the user (that is, most small
* decimal numbers will be represented in a way that when converted
* back into a string are exactly the same as what the user typed.) */
l
=
snprintf
(
buf
,
len
,
"%.17Lf"
,
value
);
if
(
l
+
1
>
len
)
return
0
;
/* No room. */
/* Now remove trailing zeroes after the '.' */
if
(
strchr
(
buf
,
'.'
)
!=
NULL
)
{
char
*
p
=
buf
+
l
-
1
;
while
(
*
p
==
'0'
)
{
p
--
;
l
--
;
}
if
(
*
p
==
'.'
)
l
--
;
}
if
(
*
p
==
'.'
)
l
--
;
break
;
default:
return
0
;
/* Invalid mode. */
}
}
else
{
l
=
snprintf
(
buf
,
len
,
"%.17Lg"
,
value
);
if
(
l
+
1
>
len
)
return
0
;
/* No room. */
}
buf
[
l
]
=
'\0'
;
return
l
;
...
...
src/util.h
View file @
bbdbfabf
...
...
@@ -38,6 +38,13 @@
* This should be the size of the buffer given to ld2string */
#define MAX_LONG_DOUBLE_CHARS 5*1024
/* long double to string convertion options */
typedef
enum
{
LD_STR_AUTO
,
/* %.17Lg */
LD_STR_HUMAN
,
/* %.17Lf + Trimming of trailing zeros */
LD_STR_HEX
/* %La */
}
ld2string_mode
;
int
stringmatchlen
(
const
char
*
p
,
int
plen
,
const
char
*
s
,
int
slen
,
int
nocase
);
int
stringmatch
(
const
char
*
p
,
const
char
*
s
,
int
nocase
);
int
stringmatchlen_fuzz_test
(
void
);
...
...
@@ -49,7 +56,7 @@ int string2ll(const char *s, size_t slen, long long *value);
int
string2l
(
const
char
*
s
,
size_t
slen
,
long
*
value
);
int
string2ld
(
const
char
*
s
,
size_t
slen
,
long
double
*
dp
);
int
d2string
(
char
*
buf
,
size_t
len
,
double
value
);
int
ld2string
(
char
*
buf
,
size_t
len
,
long
double
value
,
int
humanfriendly
);
int
ld2string
(
char
*
buf
,
size_t
len
,
long
double
value
,
ld2string_mode
mode
);
sds
getAbsolutePath
(
char
*
filename
);
unsigned
long
getTimeZone
(
void
);
int
pathIsBaseName
(
char
*
path
);
...
...
tests/modules/testrdb.c
View file @
bbdbfabf
...
...
@@ -15,11 +15,16 @@ RedisModuleString *after_str = NULL;
void
*
testrdb_type_load
(
RedisModuleIO
*
rdb
,
int
encver
)
{
int
count
=
RedisModule_LoadSigned
(
rdb
);
RedisModuleString
*
str
=
RedisModule_LoadString
(
rdb
);
float
f
=
RedisModule_LoadFloat
(
rdb
);
long
double
ld
=
RedisModule_LoadLongDouble
(
rdb
);
if
(
RedisModule_IsIOError
(
rdb
))
return
NULL
;
/* Using the values only after checking for io errors. */
assert
(
count
==
1
);
assert
(
encver
==
1
);
RedisModuleString
*
str
=
RedisModule_LoadString
(
rdb
);
assert
(
f
==
1
.
5
f
);
assert
(
ld
==
0
.
333333333333333333L
);
return
str
;
}
...
...
@@ -27,6 +32,8 @@ void testrdb_type_save(RedisModuleIO *rdb, void *value) {
RedisModuleString
*
str
=
(
RedisModuleString
*
)
value
;
RedisModule_SaveSigned
(
rdb
,
1
);
RedisModule_SaveString
(
rdb
,
str
);
RedisModule_SaveFloat
(
rdb
,
1
.
5
);
RedisModule_SaveLongDouble
(
rdb
,
0
.
333333333333333333L
);
}
void
testrdb_aux_save
(
RedisModuleIO
*
rdb
,
int
when
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment