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
hiredis
Commits
d76e13b6
Commit
d76e13b6
authored
Jul 25, 2015
by
clark.kang
Committed by
Jan-Erik Rediger
Apr 20, 2016
Browse files
apply sds from redis
parent
1b8ed388
Changes
2
Hide whitespace changes
Inline
Side-by-side
sds.c
View file @
d76e13b6
/* SDS
(Simple Dynamic Strings)
, A C dynamic strings library
.
/* SDS
Lib
, A C dynamic strings library
*
*
* Copyright (c) 2006-201
4
, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-201
2
, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* Redistribution and use in source and binary forms, with or without
...
@@ -33,9 +33,36 @@
...
@@ -33,9 +33,36 @@
#include <string.h>
#include <string.h>
#include <ctype.h>
#include <ctype.h>
#include <assert.h>
#include <assert.h>
#include "sds.h"
#include "sds.h"
static
inline
int
sdsHdrSize
(
char
type
)
{
switch
(
type
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
return
sizeof
(
struct
sdshdr5
);
case
SDS_TYPE_8
:
return
sizeof
(
struct
sdshdr8
);
case
SDS_TYPE_16
:
return
sizeof
(
struct
sdshdr16
);
case
SDS_TYPE_32
:
return
sizeof
(
struct
sdshdr32
);
case
SDS_TYPE_64
:
return
sizeof
(
struct
sdshdr64
);
}
return
0
;
}
static
inline
char
sdsReqType
(
size_t
string_size
)
{
if
(
string_size
<
32
)
return
SDS_TYPE_5
;
if
(
string_size
<
0xff
)
return
SDS_TYPE_8
;
if
(
string_size
<
0xffff
)
return
SDS_TYPE_16
;
if
(
string_size
<
0xffffffff
)
return
SDS_TYPE_32
;
return
SDS_TYPE_64
;
}
/* Create a new sds string with the content specified by the 'init' pointer
/* Create a new sds string with the content specified by the 'init' pointer
* and 'initlen'.
* and 'initlen'.
* If NULL is used for 'init' the string is initialized with zero bytes.
* If NULL is used for 'init' the string is initialized with zero bytes.
...
@@ -43,26 +70,65 @@
...
@@ -43,26 +70,65 @@
* The string is always null-termined (all the sds strings are, always) so
* The string is always null-termined (all the sds strings are, always) so
* even if you create an sds string with:
* even if you create an sds string with:
*
*
* mystring = sdsnewlen("abc",3
"
);
* mystring = sdsnewlen("abc",3);
*
*
* You can print the string with printf() as there is an implicit \0 at the
* You can print the string with printf() as there is an implicit \0 at the
* end of the string. However the string is binary safe and can contain
* end of the string. However the string is binary safe and can contain
* \0 characters in the middle, as the length is stored in the sds header. */
* \0 characters in the middle, as the length is stored in the sds header. */
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
)
{
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
)
{
struct
sdshdr
*
sh
;
void
*
sh
;
sds
s
;
if
(
init
)
{
char
type
=
sdsReqType
(
initlen
);
sh
=
malloc
(
sizeof
*
sh
+
initlen
+
1
);
/* Empty strings are usually created in order to append. Use type 8
}
else
{
* since type 5 is not good at this. */
sh
=
calloc
(
sizeof
*
sh
+
initlen
+
1
,
1
);
if
(
type
==
SDS_TYPE_5
&&
initlen
==
0
)
type
=
SDS_TYPE_8
;
}
int
hdrlen
=
sdsHdrSize
(
type
);
unsigned
char
*
fp
;
/* flags pointer. */
sh
=
malloc
(
hdrlen
+
initlen
+
1
);
if
(
!
init
)
memset
(
sh
,
0
,
hdrlen
+
initlen
+
1
);
if
(
sh
==
NULL
)
return
NULL
;
if
(
sh
==
NULL
)
return
NULL
;
sh
->
len
=
initlen
;
s
=
(
char
*
)
sh
+
hdrlen
;
sh
->
free
=
0
;
fp
=
((
unsigned
char
*
)
s
)
-
1
;
switch
(
type
)
{
case
SDS_TYPE_5
:
{
*
fp
=
type
|
(
initlen
<<
SDS_TYPE_BITS
);
break
;
}
case
SDS_TYPE_8
:
{
SDS_HDR_VAR
(
8
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
break
;
}
case
SDS_TYPE_16
:
{
SDS_HDR_VAR
(
16
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
break
;
}
case
SDS_TYPE_32
:
{
SDS_HDR_VAR
(
32
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
break
;
}
case
SDS_TYPE_64
:
{
SDS_HDR_VAR
(
64
,
s
);
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
break
;
}
}
if
(
initlen
&&
init
)
if
(
initlen
&&
init
)
memcpy
(
s
h
->
buf
,
init
,
initlen
);
memcpy
(
s
,
init
,
initlen
);
s
h
->
buf
[
initlen
]
=
'\0'
;
s
[
initlen
]
=
'\0'
;
return
(
char
*
)
sh
->
buf
;
return
s
;
}
}
/* Create an empty (zero length) sds string. Even in this case the string
/* Create an empty (zero length) sds string. Even in this case the string
...
@@ -71,7 +137,7 @@ sds sdsempty(void) {
...
@@ -71,7 +137,7 @@ sds sdsempty(void) {
return
sdsnewlen
(
""
,
0
);
return
sdsnewlen
(
""
,
0
);
}
}
/* Create a new sds string starting from a null termined C string. */
/* Create a new sds string starting from a null termin
at
ed C string. */
sds
sdsnew
(
const
char
*
init
)
{
sds
sdsnew
(
const
char
*
init
)
{
size_t
initlen
=
(
init
==
NULL
)
?
0
:
strlen
(
init
);
size_t
initlen
=
(
init
==
NULL
)
?
0
:
strlen
(
init
);
return
sdsnewlen
(
init
,
initlen
);
return
sdsnewlen
(
init
,
initlen
);
...
@@ -85,7 +151,7 @@ sds sdsdup(const sds s) {
...
@@ -85,7 +151,7 @@ sds sdsdup(const sds s) {
/* Free an sds string. No operation is performed if 's' is NULL. */
/* Free an sds string. No operation is performed if 's' is NULL. */
void
sdsfree
(
sds
s
)
{
void
sdsfree
(
sds
s
)
{
if
(
s
==
NULL
)
return
;
if
(
s
==
NULL
)
return
;
free
(
s
-
sizeof
(
struct
sdshdr
));
free
(
(
char
*
)
s
-
sdsHdrSize
(
s
[
-
1
]
));
}
}
/* Set the sds string length to the length as obtained with strlen(), so
/* Set the sds string length to the length as obtained with strlen(), so
...
@@ -103,21 +169,17 @@ void sdsfree(sds s) {
...
@@ -103,21 +169,17 @@ void sdsfree(sds s) {
* the output will be "6" as the string was modified but the logical length
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
* remains 6 bytes. */
void
sdsupdatelen
(
sds
s
)
{
void
sdsupdatelen
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
int
reallen
=
strlen
(
s
);
int
reallen
=
strlen
(
s
);
sh
->
free
+=
(
sh
->
len
-
reallen
);
sdssetlen
(
s
,
reallen
);
sh
->
len
=
reallen
;
}
}
/* Modify an sds string
o
n-place to make it empty (zero length).
/* Modify an sds string
i
n-place to make it empty (zero length).
* However all the existing buffer is not discarded but set as free space
* However all the existing buffer is not discarded but set as free space
* so that next append operations will not require allocations up to the
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
* number of bytes previously available. */
void
sdsclear
(
sds
s
)
{
void
sdsclear
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
sdssetlen
(
s
,
0
);
sh
->
free
+=
sh
->
len
;
s
[
0
]
=
'\0'
;
sh
->
len
=
0
;
sh
->
buf
[
0
]
=
'\0'
;
}
}
/* Enlarge the free space at the end of the sds string so that the caller
/* Enlarge the free space at the end of the sds string so that the caller
...
@@ -127,23 +189,48 @@ void sdsclear(sds s) {
...
@@ -127,23 +189,48 @@ void sdsclear(sds s) {
* Note: this does not change the *length* of the sds string as returned
* Note: this does not change the *length* of the sds string as returned
* by sdslen(), but only the free buffer space we have. */
* by sdslen(), but only the free buffer space we have. */
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
)
{
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
)
{
struct
sdshdr
*
sh
,
*
newsh
;
void
*
sh
,
*
newsh
;
size_t
free
=
sdsavail
(
s
);
size_t
avail
=
sdsavail
(
s
);
size_t
len
,
newlen
;
size_t
len
,
newlen
;
char
type
,
oldtype
=
s
[
-
1
]
&
SDS_TYPE_MASK
;
int
hdrlen
;
/* Return ASAP if there is enough space left. */
if
(
avail
>=
addlen
)
return
s
;
if
(
free
>=
addlen
)
return
s
;
len
=
sdslen
(
s
);
len
=
sdslen
(
s
);
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
sh
=
(
char
*
)
s
-
sdsHdrSize
(
oldtype
);
newlen
=
(
len
+
addlen
);
newlen
=
(
len
+
addlen
);
if
(
newlen
<
SDS_MAX_PREALLOC
)
if
(
newlen
<
SDS_MAX_PREALLOC
)
newlen
*=
2
;
newlen
*=
2
;
else
else
newlen
+=
SDS_MAX_PREALLOC
;
newlen
+=
SDS_MAX_PREALLOC
;
newsh
=
realloc
(
sh
,
sizeof
*
newsh
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
newsh
->
free
=
newlen
-
len
;
type
=
sdsReqType
(
newlen
);
return
newsh
->
buf
;
/* Don't use type 5: the user is appending to the string and type 5 is
* not able to remember empty space, so sdsMakeRoomFor() must be called
* at every appending operation. */
if
(
type
==
SDS_TYPE_5
)
type
=
SDS_TYPE_8
;
hdrlen
=
sdsHdrSize
(
type
);
if
(
oldtype
==
type
)
{
newsh
=
realloc
(
sh
,
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
s
=
(
char
*
)
newsh
+
hdrlen
;
}
else
{
/* Since the header size changes, need to move the string forward,
* and can't use realloc */
newsh
=
malloc
(
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
free
(
sh
);
s
=
(
char
*
)
newsh
+
hdrlen
;
s
[
-
1
]
=
type
;
sdssetlen
(
s
,
len
);
}
sdssetalloc
(
s
,
newlen
);
return
s
;
}
}
/* Reallocate the sds string so that it has no free space at the end. The
/* Reallocate the sds string so that it has no free space at the end. The
...
@@ -153,12 +240,29 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
...
@@ -153,12 +240,29 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
* After the call, the passed sds string is no longer valid and all the
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
sds
sdsRemoveFreeSpace
(
sds
s
)
{
sds
sdsRemoveFreeSpace
(
sds
s
)
{
struct
sdshdr
*
sh
;
void
*
sh
,
*
newsh
;
char
type
,
oldtype
=
s
[
-
1
]
&
SDS_TYPE_MASK
;
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
int
hdrlen
;
sh
=
realloc
(
sh
,
sizeof
*
sh
+
sh
->
len
+
1
);
size_t
len
=
sdslen
(
s
);
sh
->
free
=
0
;
sh
=
(
char
*
)
s
-
sdsHdrSize
(
oldtype
);
return
sh
->
buf
;
type
=
sdsReqType
(
len
);
hdrlen
=
sdsHdrSize
(
type
);
if
(
oldtype
==
type
)
{
newsh
=
realloc
(
sh
,
hdrlen
+
len
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
s
=
(
char
*
)
newsh
+
hdrlen
;
}
else
{
newsh
=
malloc
(
hdrlen
+
len
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
free
(
sh
);
s
=
(
char
*
)
newsh
+
hdrlen
;
s
[
-
1
]
=
type
;
sdssetlen
(
s
,
len
);
}
sdssetalloc
(
s
,
len
);
return
s
;
}
}
/* Return the total size of the allocation of the specifed sds string,
/* Return the total size of the allocation of the specifed sds string,
...
@@ -169,9 +273,8 @@ sds sdsRemoveFreeSpace(sds s) {
...
@@ -169,9 +273,8 @@ sds sdsRemoveFreeSpace(sds s) {
* 4) The implicit null term.
* 4) The implicit null term.
*/
*/
size_t
sdsAllocSize
(
sds
s
)
{
size_t
sdsAllocSize
(
sds
s
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
size_t
alloc
=
sdsalloc
(
s
);
return
sdsHdrSize
(
s
[
-
1
])
+
alloc
+
1
;
return
sizeof
(
*
sh
)
+
sh
->
len
+
sh
->
free
+
1
;
}
}
/* Increment the sds length and decrements the left free space at the
/* Increment the sds length and decrements the left free space at the
...
@@ -198,13 +301,44 @@ size_t sdsAllocSize(sds s) {
...
@@ -198,13 +301,44 @@ size_t sdsAllocSize(sds s) {
* sdsIncrLen(s, nread);
* sdsIncrLen(s, nread);
*/
*/
void
sdsIncrLen
(
sds
s
,
int
incr
)
{
void
sdsIncrLen
(
sds
s
,
int
incr
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
unsigned
char
flags
=
s
[
-
1
];
size_t
len
;
assert
(
sh
->
free
>=
incr
);
switch
(
flags
&
SDS_TYPE_MASK
)
{
sh
->
len
+=
incr
;
case
SDS_TYPE_5
:
{
sh
->
free
-=
incr
;
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
assert
(
sh
->
free
>=
0
);
unsigned
char
oldlen
=
SDS_TYPE_5_LEN
(
flags
);
s
[
sh
->
len
]
=
'\0'
;
assert
((
incr
>
0
&&
oldlen
+
incr
<
32
)
||
(
incr
<
0
&&
oldlen
>=
(
unsigned
int
)(
-
incr
)));
*
fp
=
SDS_TYPE_5
|
((
oldlen
+
incr
)
<<
SDS_TYPE_BITS
);
len
=
oldlen
+
incr
;
break
;
}
case
SDS_TYPE_8
:
{
SDS_HDR_VAR
(
8
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
case
SDS_TYPE_16
:
{
SDS_HDR_VAR
(
16
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
case
SDS_TYPE_32
:
{
SDS_HDR_VAR
(
32
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
unsigned
int
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
case
SDS_TYPE_64
:
{
SDS_HDR_VAR
(
64
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
uint64_t
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
uint64_t
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
break
;
}
default:
len
=
0
;
/* Just to avoid compilation warnings. */
}
s
[
len
]
=
'\0'
;
}
}
/* Grow the sds to have the specified length. Bytes that were not part of
/* Grow the sds to have the specified length. Bytes that were not part of
...
@@ -213,19 +347,15 @@ void sdsIncrLen(sds s, int incr) {
...
@@ -213,19 +347,15 @@ void sdsIncrLen(sds s, int incr) {
* if the specified length is smaller than the current length, no operation
* if the specified length is smaller than the current length, no operation
* is performed. */
* is performed. */
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
size_t
curlen
=
sdslen
(
s
);
size_t
totlen
,
curlen
=
sh
->
len
;
if
(
len
<=
curlen
)
return
s
;
if
(
len
<=
curlen
)
return
s
;
s
=
sdsMakeRoomFor
(
s
,
len
-
curlen
);
s
=
sdsMakeRoomFor
(
s
,
len
-
curlen
);
if
(
s
==
NULL
)
return
NULL
;
if
(
s
==
NULL
)
return
NULL
;
/* Make sure added region doesn't contain garbage */
/* Make sure added region doesn't contain garbage */
sh
=
(
void
*
)(
s
-
sizeof
*
sh
);
memset
(
s
+
curlen
,
0
,(
len
-
curlen
+
1
));
/* also set trailing \0 byte */
memset
(
s
+
curlen
,
0
,(
len
-
curlen
+
1
));
/* also set trailing \0 byte */
totlen
=
sh
->
len
+
sh
->
free
;
sdssetlen
(
s
,
len
);
sh
->
len
=
len
;
sh
->
free
=
totlen
-
sh
->
len
;
return
s
;
return
s
;
}
}
...
@@ -235,15 +365,12 @@ sds sdsgrowzero(sds s, size_t len) {
...
@@ -235,15 +365,12 @@ sds sdsgrowzero(sds s, size_t len) {
* After the call, the passed sds string is no longer valid and all the
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
)
{
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
)
{
struct
sdshdr
*
sh
;
size_t
curlen
=
sdslen
(
s
);
size_t
curlen
=
sdslen
(
s
);
s
=
sdsMakeRoomFor
(
s
,
len
);
s
=
sdsMakeRoomFor
(
s
,
len
);
if
(
s
==
NULL
)
return
NULL
;
if
(
s
==
NULL
)
return
NULL
;
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
memcpy
(
s
+
curlen
,
t
,
len
);
memcpy
(
s
+
curlen
,
t
,
len
);
sh
->
len
=
curlen
+
len
;
sdssetlen
(
s
,
curlen
+
len
);
sh
->
free
=
sh
->
free
-
len
;
s
[
curlen
+
len
]
=
'\0'
;
s
[
curlen
+
len
]
=
'\0'
;
return
s
;
return
s
;
}
}
...
@@ -267,19 +394,13 @@ sds sdscatsds(sds s, const sds t) {
...
@@ -267,19 +394,13 @@ sds sdscatsds(sds s, const sds t) {
/* Destructively modify the sds string 's' to hold the specified binary
/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
* safe string pointed by 't' of length 'len' bytes. */
sds
sdscpylen
(
sds
s
,
const
char
*
t
,
size_t
len
)
{
sds
sdscpylen
(
sds
s
,
const
char
*
t
,
size_t
len
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
if
(
sdsalloc
(
s
)
<
len
)
{
size_t
totlen
=
sh
->
free
+
sh
->
len
;
s
=
sdsMakeRoomFor
(
s
,
len
-
sdslen
(
s
));
if
(
totlen
<
len
)
{
s
=
sdsMakeRoomFor
(
s
,
len
-
sh
->
len
);
if
(
s
==
NULL
)
return
NULL
;
if
(
s
==
NULL
)
return
NULL
;
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
totlen
=
sh
->
free
+
sh
->
len
;
}
}
memcpy
(
s
,
t
,
len
);
memcpy
(
s
,
t
,
len
);
s
[
len
]
=
'\0'
;
s
[
len
]
=
'\0'
;
sh
->
len
=
len
;
sdssetlen
(
s
,
len
);
sh
->
free
=
totlen
-
len
;
return
s
;
return
s
;
}
}
...
@@ -356,27 +477,52 @@ int sdsull2str(char *s, unsigned long long v) {
...
@@ -356,27 +477,52 @@ int sdsull2str(char *s, unsigned long long v) {
return
l
;
return
l
;
}
}
/* Like sdscatpritf() but gets va_list instead of being variadic. */
/* Create an sds string from a long long value. It is much faster than:
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
sds
sdsfromlonglong
(
long
long
value
)
{
char
buf
[
SDS_LLSTR_SIZE
];
int
len
=
sdsll2str
(
buf
,
value
);
return
sdsnewlen
(
buf
,
len
);
}
/* Like sdscatprintf() but gets va_list instead of being variadic. */
sds
sdscatvprintf
(
sds
s
,
const
char
*
fmt
,
va_list
ap
)
{
sds
sdscatvprintf
(
sds
s
,
const
char
*
fmt
,
va_list
ap
)
{
va_list
cpy
;
va_list
cpy
;
char
*
buf
,
*
t
;
char
staticbuf
[
1024
],
*
buf
=
static
buf
,
*
t
;
size_t
buflen
=
16
;
size_t
buflen
=
strlen
(
fmt
)
*
2
;
while
(
1
)
{
/* We try to start using a static buffer for speed.
* If not possible we revert to heap allocation. */
if
(
buflen
>
sizeof
(
staticbuf
))
{
buf
=
malloc
(
buflen
);
buf
=
malloc
(
buflen
);
if
(
buf
==
NULL
)
return
NULL
;
if
(
buf
==
NULL
)
return
NULL
;
}
else
{
buflen
=
sizeof
(
staticbuf
);
}
/* Try with buffers two times bigger every time we fail to
* fit the string in the current buffer size. */
while
(
1
)
{
buf
[
buflen
-
2
]
=
'\0'
;
buf
[
buflen
-
2
]
=
'\0'
;
va_copy
(
cpy
,
ap
);
va_copy
(
cpy
,
ap
);
vsnprintf
(
buf
,
buflen
,
fmt
,
cpy
);
vsnprintf
(
buf
,
buflen
,
fmt
,
cpy
);
va_end
(
cpy
);
if
(
buf
[
buflen
-
2
]
!=
'\0'
)
{
if
(
buf
[
buflen
-
2
]
!=
'\0'
)
{
free
(
buf
);
if
(
buf
!=
staticbuf
)
free
(
buf
);
buflen
*=
2
;
buflen
*=
2
;
buf
=
malloc
(
buflen
);
if
(
buf
==
NULL
)
return
NULL
;
continue
;
continue
;
}
}
break
;
break
;
}
}
/* Finally concat the obtained string to the SDS string and return it. */
t
=
sdscat
(
s
,
buf
);
t
=
sdscat
(
s
,
buf
);
free
(
buf
);
if
(
buf
!=
staticbuf
)
free
(
buf
);
return
t
;
return
t
;
}
}
...
@@ -389,7 +535,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
...
@@ -389,7 +535,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
* Example:
* Example:
*
*
* s = sdsnew("Sum is: ");
* s = sdsnew("Sum is: ");
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b)
;
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b)
.
*
*
* Often you need to create a string from scratch with the printf-alike
* Often you need to create a string from scratch with the printf-alike
* format. When this is the need, just use sdsempty() as the target string:
* format. When this is the need, just use sdsempty() as the target string:
...
@@ -419,11 +565,9 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
...
@@ -419,11 +565,9 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
* %I - 64 bit signed integer (long long, int64_t)
* %I - 64 bit signed integer (long long, int64_t)
* %u - unsigned int
* %u - unsigned int
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %T - A size_t variable.
* %% - Verbatim "%" character.
* %% - Verbatim "%" character.
*/
*/
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...)
{
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
initlen
=
sdslen
(
s
);
size_t
initlen
=
sdslen
(
s
);
const
char
*
f
=
fmt
;
const
char
*
f
=
fmt
;
int
i
;
int
i
;
...
@@ -434,14 +578,13 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
...
@@ -434,14 +578,13 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
i
=
initlen
;
/* Position of the next byte to write to dest str. */
i
=
initlen
;
/* Position of the next byte to write to dest str. */
while
(
*
f
)
{
while
(
*
f
)
{
char
next
,
*
str
;
char
next
,
*
str
;
in
t
l
;
size_
t
l
;
long
long
num
;
long
long
num
;
unsigned
long
long
unum
;
unsigned
long
long
unum
;
/* Make sure there is always space for at least 1 char. */
/* Make sure there is always space for at least 1 char. */
if
(
s
h
->
free
==
0
)
{
if
(
s
dsavail
(
s
)
==
0
)
{
s
=
sdsMakeRoomFor
(
s
,
1
);
s
=
sdsMakeRoomFor
(
s
,
1
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
}
switch
(
*
f
)
{
switch
(
*
f
)
{
...
@@ -453,13 +596,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
...
@@ -453,13 +596,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
case
'S'
:
case
'S'
:
str
=
va_arg
(
ap
,
char
*
);
str
=
va_arg
(
ap
,
char
*
);
l
=
(
next
==
's'
)
?
strlen
(
str
)
:
sdslen
(
str
);
l
=
(
next
==
's'
)
?
strlen
(
str
)
:
sdslen
(
str
);
if
(
s
h
->
free
<
l
)
{
if
(
s
dsavail
(
s
)
<
l
)
{
s
=
sdsMakeRoomFor
(
s
,
l
);
s
=
sdsMakeRoomFor
(
s
,
l
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
}
memcpy
(
s
+
i
,
str
,
l
);
memcpy
(
s
+
i
,
str
,
l
);
sh
->
len
+=
l
;
sdsinclen
(
s
,
l
);
sh
->
free
-=
l
;
i
+=
l
;
i
+=
l
;
break
;
break
;
case
'i'
:
case
'i'
:
...
@@ -471,49 +612,40 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
...
@@ -471,49 +612,40 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
{
{
char
buf
[
SDS_LLSTR_SIZE
];
char
buf
[
SDS_LLSTR_SIZE
];
l
=
sdsll2str
(
buf
,
num
);
l
=
sdsll2str
(
buf
,
num
);
if
(
s
h
->
free
<
l
)
{
if
(
s
dsavail
(
s
)
<
l
)
{
s
=
sdsMakeRoomFor
(
s
,
l
);
s
=
sdsMakeRoomFor
(
s
,
l
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
}
memcpy
(
s
+
i
,
buf
,
l
);
memcpy
(
s
+
i
,
buf
,
l
);
sh
->
len
+=
l
;
sdsinclen
(
s
,
l
);
sh
->
free
-=
l
;
i
+=
l
;
i
+=
l
;
}
}
break
;
break
;
case
'u'
:
case
'u'
:
case
'U'
:
case
'U'
:
case
'T'
:
if
(
next
==
'u'
)
if
(
next
==
'u'
)
unum
=
va_arg
(
ap
,
unsigned
int
);
unum
=
va_arg
(
ap
,
unsigned
int
);
else
if
(
next
==
'U'
)
unum
=
va_arg
(
ap
,
unsigned
long
long
);
else
else
unum
=
(
unsigned
long
long
)
va_arg
(
ap
,
size_t
)
;
unum
=
va_arg
(
ap
,
unsigned
long
long
);
{
{
char
buf
[
SDS_LLSTR_SIZE
];
char
buf
[
SDS_LLSTR_SIZE
];
l
=
sdsull2str
(
buf
,
unum
);
l
=
sdsull2str
(
buf
,
unum
);
if
(
s
h
->
free
<
l
)
{
if
(
s
dsavail
(
s
)
<
l
)
{
s
=
sdsMakeRoomFor
(
s
,
l
);
s
=
sdsMakeRoomFor
(
s
,
l
);
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
}
}
memcpy
(
s
+
i
,
buf
,
l
);
memcpy
(
s
+
i
,
buf
,
l
);
sh
->
len
+=
l
;
sdsinclen
(
s
,
l
);
sh
->
free
-=
l
;
i
+=
l
;
i
+=
l
;
}
}
break
;
break
;
default:
/* Handle %% and generally %<unknown>. */
default:
/* Handle %% and generally %<unknown>. */
s
[
i
++
]
=
next
;
s
[
i
++
]
=
next
;
sh
->
len
+=
1
;
sdsinclen
(
s
,
1
);
sh
->
free
-=
1
;
break
;
break
;
}
}
break
;
break
;
default:
default:
s
[
i
++
]
=
*
f
;
s
[
i
++
]
=
*
f
;
sh
->
len
+=
1
;
sdsinclen
(
s
,
1
);
sh
->
free
-=
1
;
break
;
break
;
}
}
f
++
;
f
++
;
...
@@ -525,7 +657,6 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
...
@@ -525,7 +657,6 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
return
s
;
return
s
;
}
}
/* Remove the part of the string from left and from right composed just of
/* Remove the part of the string from left and from right composed just of
* contiguous characters found in 'cset', that is a null terminted C string.
* contiguous characters found in 'cset', that is a null terminted C string.
*
*
...
@@ -535,25 +666,24 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
...
@@ -535,25 +666,24 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
* Example:
* Example:
*
*
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
* s = sdstrim(s,"A. :");
* s = sdstrim(s,"A
a
. :");
* printf("%s\n", s);
* printf("%s\n", s);
*
*
* Output will be just "Hello World".
* Output will be just "Hello World".
*/
*/
void
sdstrim
(
sds
s
,
const
char
*
cset
)
{
sds
sdstrim
(
sds
s
,
const
char
*
cset
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
char
*
start
,
*
end
,
*
sp
,
*
ep
;
char
*
start
,
*
end
,
*
sp
,
*
ep
;
size_t
len
;
size_t
len
;
sp
=
start
=
s
;
sp
=
start
=
s
;
ep
=
end
=
s
+
sdslen
(
s
)
-
1
;
ep
=
end
=
s
+
sdslen
(
s
)
-
1
;
while
(
sp
<=
end
&&
strchr
(
cset
,
*
sp
))
sp
++
;
while
(
sp
<=
end
&&
strchr
(
cset
,
*
sp
))
sp
++
;
while
(
ep
>
s
tart
&&
strchr
(
cset
,
*
ep
))
ep
--
;
while
(
ep
>
s
p
&&
strchr
(
cset
,
*
ep
))
ep
--
;
len
=
(
sp
>
ep
)
?
0
:
((
ep
-
sp
)
+
1
);
len
=
(
sp
>
ep
)
?
0
:
((
ep
-
sp
)
+
1
);
if
(
s
h
->
buf
!=
sp
)
memmove
(
s
h
->
buf
,
sp
,
len
);
if
(
s
!=
sp
)
memmove
(
s
,
sp
,
len
);
s
h
->
buf
[
len
]
=
'\0'
;
s
[
len
]
=
'\0'
;
s
h
->
free
=
sh
->
free
+
(
sh
->
len
-
len
);
s
dssetlen
(
s
,
len
);
sh
->
len
=
len
;
return
s
;
}
}
/* Turn the string into a smaller (or equal) string containing only the
/* Turn the string into a smaller (or equal) string containing only the
...
@@ -573,7 +703,6 @@ void sdstrim(sds s, const char *cset) {
...
@@ -573,7 +703,6 @@ void sdstrim(sds s, const char *cset) {
* sdsrange(s,1,-1); => "ello World"
* sdsrange(s,1,-1); => "ello World"
*/
*/
void
sdsrange
(
sds
s
,
int
start
,
int
end
)
{
void
sdsrange
(
sds
s
,
int
start
,
int
end
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
sizeof
*
sh
);
size_t
newlen
,
len
=
sdslen
(
s
);
size_t
newlen
,
len
=
sdslen
(
s
);
if
(
len
==
0
)
return
;
if
(
len
==
0
)
return
;
...
@@ -596,10 +725,9 @@ void sdsrange(sds s, int start, int end) {
...
@@ -596,10 +725,9 @@ void sdsrange(sds s, int start, int end) {
}
else
{
}
else
{
start
=
0
;
start
=
0
;
}
}
if
(
start
&&
newlen
)
memmove
(
sh
->
buf
,
sh
->
buf
+
start
,
newlen
);
if
(
start
&&
newlen
)
memmove
(
s
,
s
+
start
,
newlen
);
sh
->
buf
[
newlen
]
=
0
;
s
[
newlen
]
=
0
;
sh
->
free
=
sh
->
free
+
(
sh
->
len
-
newlen
);
sdssetlen
(
s
,
newlen
);
sh
->
len
=
newlen
;
}
}
/* Apply tolower() to every character of the sds string 's'. */
/* Apply tolower() to every character of the sds string 's'. */
...
@@ -620,8 +748,8 @@ void sdstoupper(sds s) {
...
@@ -620,8 +748,8 @@ void sdstoupper(sds s) {
*
*
* Return value:
* Return value:
*
*
*
1
if s1 > s2.
*
positive
if s1 > s2.
*
-1
if s1 < s2.
*
negative
if s1 < s2.
* 0 if s1 and s2 are exactly the same binary string.
* 0 if s1 and s2 are exactly the same binary string.
*
*
* If two strings share exactly the same prefix, but one of the two has
* If two strings share exactly the same prefix, but one of the two has
...
@@ -712,25 +840,6 @@ void sdsfreesplitres(sds *tokens, int count) {
...
@@ -712,25 +840,6 @@ void sdsfreesplitres(sds *tokens, int count) {
free
(
tokens
);
free
(
tokens
);
}
}
/* Create an sds string from a long long value. It is much faster than:
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
sds
sdsfromlonglong
(
long
long
value
)
{
char
buf
[
32
],
*
p
;
unsigned
long
long
v
;
v
=
(
value
<
0
)
?
-
value
:
value
;
p
=
buf
+
31
;
/* point to the last character */
do
{
*
p
--
=
'0'
+
(
v
%
10
);
v
/=
10
;
}
while
(
v
);
if
(
value
<
0
)
*
p
--
=
'-'
;
p
++
;
return
sdsnewlen
(
p
,
32
-
(
p
-
buf
));
}
/* Append to the sds string "s" an escaped string representation where
/* Append to the sds string "s" an escaped string representation where
* all the non-printable characters (tested with isprint()) are turned into
* all the non-printable characters (tested with isprint()) are turned into
* escapes in the form "\n\r\a...." or "\x<hex-number>".
* escapes in the form "\n\r\a...." or "\x<hex-number>".
...
@@ -947,36 +1056,25 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
...
@@ -947,36 +1056,25 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
/* Join an array of C strings using the specified separator (also a C string).
/* Join an array of C strings using the specified separator (also a C string).
* Returns the result as an sds string. */
* Returns the result as an sds string. */
sds
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
,
size_t
seplen
)
{
sds
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
)
{
sds
join
=
sdsempty
();
sds
join
=
sdsempty
();
int
j
;
int
j
;
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
join
=
sdscat
(
join
,
argv
[
j
]);
join
=
sdscat
(
join
,
argv
[
j
]);
if
(
j
!=
argc
-
1
)
join
=
sdscatlen
(
join
,
sep
,
seplen
);
if
(
j
!=
argc
-
1
)
join
=
sdscat
(
join
,
sep
);
}
return
join
;
}
/* Like sdsjoin, but joins an array of SDS strings. */
sds
sdsjoinsds
(
sds
*
argv
,
int
argc
,
const
char
*
sep
,
size_t
seplen
)
{
sds
join
=
sdsempty
();
int
j
;
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
join
=
sdscatsds
(
join
,
argv
[
j
]);
if
(
j
!=
argc
-
1
)
join
=
sdscatlen
(
join
,
sep
,
seplen
);
}
}
return
join
;
return
join
;
}
}
#ifdef
SDS_TEST_MAIN
#if
def
ined(REDIS_TEST) || defined(
SDS_TEST_MAIN
)
#include <stdio.h>
#include <stdio.h>
#include "testhelp.h"
#include "testhelp.h"
#include "limits.h"
int
main
(
void
)
{
#define UNUSED(x) (void)(x)
int
sdsTest
(
void
)
{
{
{
struct
sdshdr
*
sh
;
sds
x
=
sdsnew
(
"foo"
),
y
;
sds
x
=
sdsnew
(
"foo"
),
y
;
test_cond
(
"Create a string and obtain the length"
,
test_cond
(
"Create a string and obtain the length"
,
...
@@ -1003,7 +1101,35 @@ int main(void) {
...
@@ -1003,7 +1101,35 @@ int main(void) {
sdsfree
(
x
);
sdsfree
(
x
);
x
=
sdscatprintf
(
sdsempty
(),
"%d"
,
123
);
x
=
sdscatprintf
(
sdsempty
(),
"%d"
,
123
);
test_cond
(
"sdscatprintf() seems working in the base case"
,
test_cond
(
"sdscatprintf() seems working in the base case"
,
sdslen
(
x
)
==
3
&&
memcmp
(
x
,
"123
\0
"
,
4
)
==
0
)
sdslen
(
x
)
==
3
&&
memcmp
(
x
,
"123
\0
"
,
4
)
==
0
)
sdsfree
(
x
);
x
=
sdsnew
(
"--"
);
x
=
sdscatfmt
(
x
,
"Hello %s World %I,%I--"
,
"Hi!"
,
LLONG_MIN
,
LLONG_MAX
);
test_cond
(
"sdscatfmt() seems working in the base case"
,
sdslen
(
x
)
==
60
&&
memcmp
(
x
,
"--Hello Hi! World -9223372036854775808,"
"9223372036854775807--"
,
60
)
==
0
)
printf
(
"[%s]
\n
"
,
x
);
sdsfree
(
x
);
x
=
sdsnew
(
"--"
);
x
=
sdscatfmt
(
x
,
"%u,%U--"
,
UINT_MAX
,
ULLONG_MAX
);
test_cond
(
"sdscatfmt() seems working with unsigned numbers"
,
sdslen
(
x
)
==
35
&&
memcmp
(
x
,
"--4294967295,18446744073709551615--"
,
35
)
==
0
)
sdsfree
(
x
);
x
=
sdsnew
(
" x "
);
sdstrim
(
x
,
" x"
);
test_cond
(
"sdstrim() works when all chars match"
,
sdslen
(
x
)
==
0
)
sdsfree
(
x
);
x
=
sdsnew
(
" x "
);
sdstrim
(
x
,
" "
);
test_cond
(
"sdstrim() works when a single char remains"
,
sdslen
(
x
)
==
1
&&
x
[
0
]
==
'x'
)
sdsfree
(
x
);
sdsfree
(
x
);
x
=
sdsnew
(
"xxciaoyyy"
);
x
=
sdsnew
(
"xxciaoyyy"
);
...
@@ -1072,24 +1198,47 @@ int main(void) {
...
@@ -1072,24 +1198,47 @@ int main(void) {
memcmp
(
y
,
"
\"\\
a
\\
n
\\
x00foo
\\
r
\"
"
,
15
)
==
0
)
memcmp
(
y
,
"
\"\\
a
\\
n
\\
x00foo
\\
r
\"
"
,
15
)
==
0
)
{
{
int
oldfree
;
unsigned
int
oldfree
;
char
*
p
;
int
step
=
10
,
j
,
i
;
sdsfree
(
x
);
sdsfree
(
x
);
sdsfree
(
y
);
x
=
sdsnew
(
"0"
);
x
=
sdsnew
(
"0"
);
sh
=
(
void
*
)
(
x
-
(
sizeof
(
struct
sdshdr
)));
test_cond
(
"sdsnew() free/len buffers"
,
sdslen
(
x
)
==
1
&&
sdsavail
(
x
)
==
0
);
test_cond
(
"sdsnew() free/len buffers"
,
sh
->
len
==
1
&&
sh
->
free
==
0
);
x
=
sdsMakeRoomFor
(
x
,
1
);
/* Run the test a few times in order to hit the first two
sh
=
(
void
*
)
(
x
-
(
sizeof
(
struct
sdshdr
)));
* SDS header types. */
test_cond
(
"sdsMakeRoomFor()"
,
sh
->
len
==
1
&&
sh
->
free
>
0
);
for
(
i
=
0
;
i
<
10
;
i
++
)
{
oldfree
=
sh
->
free
;
int
oldlen
=
sdslen
(
x
);
x
[
1
]
=
'1'
;
x
=
sdsMakeRoomFor
(
x
,
step
);
sdsIncrLen
(
x
,
1
);
int
type
=
x
[
-
1
]
&
SDS_TYPE_MASK
;
test_cond
(
"sdsIncrLen() -- content"
,
x
[
0
]
==
'0'
&&
x
[
1
]
==
'1'
);
test_cond
(
"sdsIncrLen() -- len"
,
sh
->
len
==
2
);
test_cond
(
"sdsMakeRoomFor() len"
,
sdslen
(
x
)
==
oldlen
);
test_cond
(
"sdsIncrLen() -- free"
,
sh
->
free
==
oldfree
-
1
);
if
(
type
!=
SDS_TYPE_5
)
{
test_cond
(
"sdsMakeRoomFor() free"
,
sdsavail
(
x
)
>=
step
);
oldfree
=
sdsavail
(
x
);
}
p
=
x
+
oldlen
;
for
(
j
=
0
;
j
<
step
;
j
++
)
{
p
[
j
]
=
'A'
+
j
;
}
sdsIncrLen
(
x
,
step
);
}
test_cond
(
"sdsMakeRoomFor() content"
,
memcmp
(
"0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ"
,
x
,
101
)
==
0
);
test_cond
(
"sdsMakeRoomFor() final length"
,
sdslen
(
x
)
==
101
);
sdsfree
(
x
);
}
}
}
}
test_report
()
test_report
()
return
0
;
return
0
;
}
}
#endif
#endif
#ifdef SDS_TEST_MAIN
int
main
(
void
)
{
return
sdsTest
();
}
#endif
sds.h
View file @
d76e13b6
/* SDS
(Simple Dynamic Strings)
, A C dynamic strings library
.
/* SDS
Lib
, A C dynamic strings library
*
*
* Copyright (c) 2006-201
4
, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-201
0
, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* Redistribution and use in source and binary forms, with or without
...
@@ -35,35 +35,188 @@
...
@@ -35,35 +35,188 @@
#include <sys/types.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdarg.h>
#ifdef _MSC_VER
#include <stdint.h>
#include "win32.h"
#endif
typedef
char
*
sds
;
typedef
char
*
sds
;
struct
sdshdr
{
/* Note: sdshdr5 is never used, we just access the flags byte directly.
int
len
;
* However is here to document the layout of type 5 SDS strings. */
int
free
;
struct
__attribute__
((
__packed__
))
sdshdr5
{
unsigned
char
flags
;
/* 3 lsb of type, and 5 msb of string length */
char
buf
[];
};
struct
__attribute__
((
__packed__
))
sdshdr8
{
uint8_t
len
;
/* used */
uint8_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
};
struct
__attribute__
((
__packed__
))
sdshdr16
{
uint16_t
len
;
/* used */
uint16_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
char
buf
[];
};
};
struct
__attribute__
((
__packed__
))
sdshdr32
{
uint32_t
len
;
/* used */
uint32_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
};
struct
__attribute__
((
__packed__
))
sdshdr64
{
uint64_t
len
;
/* used */
uint64_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
};
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
static
inline
size_t
sdslen
(
const
sds
s
)
{
static
inline
size_t
sdslen
(
const
sds
s
)
{
struct
sdshdr
*
sh
=
(
struct
sdshdr
*
)(
s
-
sizeof
*
sh
);
unsigned
char
flags
=
s
[
-
1
];
return
sh
->
len
;
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
return
SDS_TYPE_5_LEN
(
flags
);
case
SDS_TYPE_8
:
return
SDS_HDR
(
8
,
s
)
->
len
;
case
SDS_TYPE_16
:
return
SDS_HDR
(
16
,
s
)
->
len
;
case
SDS_TYPE_32
:
return
SDS_HDR
(
32
,
s
)
->
len
;
case
SDS_TYPE_64
:
return
SDS_HDR
(
64
,
s
)
->
len
;
}
return
0
;
}
}
static
inline
size_t
sdsavail
(
const
sds
s
)
{
static
inline
size_t
sdsavail
(
const
sds
s
)
{
struct
sdshdr
*
sh
=
(
struct
sdshdr
*
)(
s
-
sizeof
*
sh
);
unsigned
char
flags
=
s
[
-
1
];
return
sh
->
free
;
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
{
return
0
;
}
case
SDS_TYPE_8
:
{
SDS_HDR_VAR
(
8
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
case
SDS_TYPE_16
:
{
SDS_HDR_VAR
(
16
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
case
SDS_TYPE_32
:
{
SDS_HDR_VAR
(
32
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
case
SDS_TYPE_64
:
{
SDS_HDR_VAR
(
64
,
s
);
return
sh
->
alloc
-
sh
->
len
;
}
}
return
0
;
}
static
inline
void
sdssetlen
(
sds
s
,
size_t
newlen
)
{
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
{
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
*
fp
=
SDS_TYPE_5
|
(
newlen
<<
SDS_TYPE_BITS
);
}
break
;
case
SDS_TYPE_8
:
SDS_HDR
(
8
,
s
)
->
len
=
newlen
;
break
;
case
SDS_TYPE_16
:
SDS_HDR
(
16
,
s
)
->
len
=
newlen
;
break
;
case
SDS_TYPE_32
:
SDS_HDR
(
32
,
s
)
->
len
=
newlen
;
break
;
case
SDS_TYPE_64
:
SDS_HDR
(
64
,
s
)
->
len
=
newlen
;
break
;
}
}
static
inline
void
sdsinclen
(
sds
s
,
size_t
inc
)
{
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
{
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
unsigned
char
newlen
=
SDS_TYPE_5_LEN
(
flags
)
+
inc
;
*
fp
=
SDS_TYPE_5
|
(
newlen
<<
SDS_TYPE_BITS
);
}
break
;
case
SDS_TYPE_8
:
SDS_HDR
(
8
,
s
)
->
len
+=
inc
;
break
;
case
SDS_TYPE_16
:
SDS_HDR
(
16
,
s
)
->
len
+=
inc
;
break
;
case
SDS_TYPE_32
:
SDS_HDR
(
32
,
s
)
->
len
+=
inc
;
break
;
case
SDS_TYPE_64
:
SDS_HDR
(
64
,
s
)
->
len
+=
inc
;
break
;
}
}
/* sdsalloc() = sdsavail() + sdslen() */
static
inline
size_t
sdsalloc
(
const
sds
s
)
{
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
return
SDS_TYPE_5_LEN
(
flags
);
case
SDS_TYPE_8
:
return
SDS_HDR
(
8
,
s
)
->
alloc
;
case
SDS_TYPE_16
:
return
SDS_HDR
(
16
,
s
)
->
alloc
;
case
SDS_TYPE_32
:
return
SDS_HDR
(
32
,
s
)
->
alloc
;
case
SDS_TYPE_64
:
return
SDS_HDR
(
64
,
s
)
->
alloc
;
}
return
0
;
}
static
inline
void
sdssetalloc
(
sds
s
,
size_t
newlen
)
{
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
SDS_TYPE_5
:
/* Nothing to do, this type has no total allocation info. */
break
;
case
SDS_TYPE_8
:
SDS_HDR
(
8
,
s
)
->
alloc
=
newlen
;
break
;
case
SDS_TYPE_16
:
SDS_HDR
(
16
,
s
)
->
alloc
=
newlen
;
break
;
case
SDS_TYPE_32
:
SDS_HDR
(
32
,
s
)
->
alloc
=
newlen
;
break
;
case
SDS_TYPE_64
:
SDS_HDR
(
64
,
s
)
->
alloc
=
newlen
;
break
;
}
}
}
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
);
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
);
sds
sdsnew
(
const
char
*
init
);
sds
sdsnew
(
const
char
*
init
);
sds
sdsempty
(
void
);
sds
sdsempty
(
void
);
size_t
sdslen
(
const
sds
s
);
sds
sdsdup
(
const
sds
s
);
sds
sdsdup
(
const
sds
s
);
void
sdsfree
(
sds
s
);
void
sdsfree
(
sds
s
);
size_t
sdsavail
(
const
sds
s
);
sds
sdsgrowzero
(
sds
s
,
size_t
len
);
sds
sdsgrowzero
(
sds
s
,
size_t
len
);
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
);
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
);
sds
sdscat
(
sds
s
,
const
char
*
t
);
sds
sdscat
(
sds
s
,
const
char
*
t
);
...
@@ -80,7 +233,7 @@ sds sdscatprintf(sds s, const char *fmt, ...);
...
@@ -80,7 +233,7 @@ sds sdscatprintf(sds s, const char *fmt, ...);
#endif
#endif
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...);
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...);
void
sdstrim
(
sds
s
,
const
char
*
cset
);
sds
sdstrim
(
sds
s
,
const
char
*
cset
);
void
sdsrange
(
sds
s
,
int
start
,
int
end
);
void
sdsrange
(
sds
s
,
int
start
,
int
end
);
void
sdsupdatelen
(
sds
s
);
void
sdsupdatelen
(
sds
s
);
void
sdsclear
(
sds
s
);
void
sdsclear
(
sds
s
);
...
@@ -93,8 +246,7 @@ sds sdsfromlonglong(long long value);
...
@@ -93,8 +246,7 @@ sds sdsfromlonglong(long long value);
sds
sdscatrepr
(
sds
s
,
const
char
*
p
,
size_t
len
);
sds
sdscatrepr
(
sds
s
,
const
char
*
p
,
size_t
len
);
sds
*
sdssplitargs
(
const
char
*
line
,
int
*
argc
);
sds
*
sdssplitargs
(
const
char
*
line
,
int
*
argc
);
sds
sdsmapchars
(
sds
s
,
const
char
*
from
,
const
char
*
to
,
size_t
setlen
);
sds
sdsmapchars
(
sds
s
,
const
char
*
from
,
const
char
*
to
,
size_t
setlen
);
sds
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
,
size_t
seplen
);
sds
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
);
sds
sdsjoinsds
(
sds
*
argv
,
int
argc
,
const
char
*
sep
,
size_t
seplen
);
/* Low level functions exposed to the user API */
/* Low level functions exposed to the user API */
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
);
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
);
...
@@ -102,4 +254,8 @@ void sdsIncrLen(sds s, int incr);
...
@@ -102,4 +254,8 @@ void sdsIncrLen(sds s, int incr);
sds
sdsRemoveFreeSpace
(
sds
s
);
sds
sdsRemoveFreeSpace
(
sds
s
);
size_t
sdsAllocSize
(
sds
s
);
size_t
sdsAllocSize
(
sds
s
);
#ifdef REDIS_TEST
int
sdsTest
(
int
argc
,
char
*
argv
[]);
#endif
#endif
#endif
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