1 /* SDSLib 2.0 -- A C dynamic strings library
2 *
3 * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
4 * Copyright (c) 2015, Oran Agra
5 * Copyright (c) 2015, Redis Labs, Inc
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Redis nor the names of its contributors may be used
17 * to endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifndef __SDS_H
34 #define __SDS_H
35
36 #define SDS_MAX_PREALLOC (1024*1024)
37
38 #include <sys/types.h>
39 #include <stdarg.h>
40 #include <stdint.h>
41
42 typedef char *sds;
43
44 /* Note: sdshdr5 is never used, we just access the flags byte directly.
45 * However is here to document the layout of type 5 SDS strings. */
46 struct __attribute__ ((__packed__)) sdshdr5 {
47 unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
48 char buf[];
49 };
50 struct __attribute__ ((__packed__)) sdshdr8 {
51 uint8_t len; /* used */
52 uint8_t alloc; /* excluding the header and null terminator */
53 unsigned char flags; /* 3 lsb of type, 5 unused bits */
54 char buf[];
55 };
56 struct __attribute__ ((__packed__)) sdshdr16 {
57 uint16_t len; /* used */
58 uint16_t alloc; /* excluding the header and null terminator */
59 unsigned char flags; /* 3 lsb of type, 5 unused bits */
60 char buf[];
61 };
62 struct __attribute__ ((__packed__)) sdshdr32 {
63 uint32_t len; /* used */
64 uint32_t alloc; /* excluding the header and null terminator */
65 unsigned char flags; /* 3 lsb of type, 5 unused bits */
66 char buf[];
67 };
68 struct __attribute__ ((__packed__)) sdshdr64 {
69 uint64_t len; /* used */
70 uint64_t alloc; /* excluding the header and null terminator */
71 unsigned char flags; /* 3 lsb of type, 5 unused bits */
72 char buf[];
73 };
74
75 #define SDS_TYPE_5 0
76 #define SDS_TYPE_8 1
77 #define SDS_TYPE_16 2
78 #define SDS_TYPE_32 3
79 #define SDS_TYPE_64 4
80 #define SDS_TYPE_MASK 7
81 #define SDS_TYPE_BITS 3
82 #define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
83 #define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
84 #define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
85
sdslen(const sds s)86 static inline size_t sdslen(const sds s) {
87 unsigned char flags = s[-1];
88 switch(flags&SDS_TYPE_MASK) {
89 case SDS_TYPE_5:
90 return SDS_TYPE_5_LEN(flags);
91 case SDS_TYPE_8:
92 return SDS_HDR(8,s)->len;
93 case SDS_TYPE_16:
94 return SDS_HDR(16,s)->len;
95 case SDS_TYPE_32:
96 return SDS_HDR(32,s)->len;
97 case SDS_TYPE_64:
98 return SDS_HDR(64,s)->len;
99 }
100 return 0;
101 }
102
sdsavail(const sds s)103 static inline size_t sdsavail(const sds s) {
104 unsigned char flags = s[-1];
105 switch(flags&SDS_TYPE_MASK) {
106 case SDS_TYPE_5: {
107 return 0;
108 }
109 case SDS_TYPE_8: {
110 SDS_HDR_VAR(8,s);
111 return sh->alloc - sh->len;
112 }
113 case SDS_TYPE_16: {
114 SDS_HDR_VAR(16,s);
115 return sh->alloc - sh->len;
116 }
117 case SDS_TYPE_32: {
118 SDS_HDR_VAR(32,s);
119 return sh->alloc - sh->len;
120 }
121 case SDS_TYPE_64: {
122 SDS_HDR_VAR(64,s);
123 return sh->alloc - sh->len;
124 }
125 }
126 return 0;
127 }
128
sdssetlen(sds s,size_t newlen)129 static inline void sdssetlen(sds s, size_t newlen) {
130 unsigned char flags = s[-1];
131 switch(flags&SDS_TYPE_MASK) {
132 case SDS_TYPE_5:
133 {
134 unsigned char *fp = ((unsigned char*)s)-1;
135 *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
136 }
137 break;
138 case SDS_TYPE_8:
139 SDS_HDR(8,s)->len = newlen;
140 break;
141 case SDS_TYPE_16:
142 SDS_HDR(16,s)->len = newlen;
143 break;
144 case SDS_TYPE_32:
145 SDS_HDR(32,s)->len = newlen;
146 break;
147 case SDS_TYPE_64:
148 SDS_HDR(64,s)->len = newlen;
149 break;
150 }
151 }
152
sdsinclen(sds s,size_t inc)153 static inline void sdsinclen(sds s, size_t inc) {
154 unsigned char flags = s[-1];
155 switch(flags&SDS_TYPE_MASK) {
156 case SDS_TYPE_5:
157 {
158 unsigned char *fp = ((unsigned char*)s)-1;
159 unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
160 *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
161 }
162 break;
163 case SDS_TYPE_8:
164 SDS_HDR(8,s)->len += inc;
165 break;
166 case SDS_TYPE_16:
167 SDS_HDR(16,s)->len += inc;
168 break;
169 case SDS_TYPE_32:
170 SDS_HDR(32,s)->len += inc;
171 break;
172 case SDS_TYPE_64:
173 SDS_HDR(64,s)->len += inc;
174 break;
175 }
176 }
177
178 /* sdsalloc() = sdsavail() + sdslen() */
sdsalloc(const sds s)179 static inline size_t sdsalloc(const sds s) {
180 unsigned char flags = s[-1];
181 switch(flags&SDS_TYPE_MASK) {
182 case SDS_TYPE_5:
183 return SDS_TYPE_5_LEN(flags);
184 case SDS_TYPE_8:
185 return SDS_HDR(8,s)->alloc;
186 case SDS_TYPE_16:
187 return SDS_HDR(16,s)->alloc;
188 case SDS_TYPE_32:
189 return SDS_HDR(32,s)->alloc;
190 case SDS_TYPE_64:
191 return SDS_HDR(64,s)->alloc;
192 }
193 return 0;
194 }
195
sdssetalloc(sds s,size_t newlen)196 static inline void sdssetalloc(sds s, size_t newlen) {
197 unsigned char flags = s[-1];
198 switch(flags&SDS_TYPE_MASK) {
199 case SDS_TYPE_5:
200 /* Nothing to do, this type has no total allocation info. */
201 break;
202 case SDS_TYPE_8:
203 SDS_HDR(8,s)->alloc = newlen;
204 break;
205 case SDS_TYPE_16:
206 SDS_HDR(16,s)->alloc = newlen;
207 break;
208 case SDS_TYPE_32:
209 SDS_HDR(32,s)->alloc = newlen;
210 break;
211 case SDS_TYPE_64:
212 SDS_HDR(64,s)->alloc = newlen;
213 break;
214 }
215 }
216
217 sds sdsnewlen(const void *init, size_t initlen);
218 sds sdsnew(const char *init);
219 sds sdsempty(void);
220 sds sdsdup(const sds s);
221 void sdsfree(sds s);
222 sds sdsgrowzero(sds s, size_t len);
223 sds sdscatlen(sds s, const void *t, size_t len);
224 sds sdscat(sds s, const char *t);
225 sds sdscatsds(sds s, const sds t);
226 sds sdscpylen(sds s, const char *t, size_t len);
227 sds sdscpy(sds s, const char *t);
228
229 sds sdscatvprintf(sds s, const char *fmt, va_list ap);
230 #ifdef __GNUC__
231 sds sdscatprintf(sds s, const char *fmt, ...)
232 __attribute__((format(printf, 2, 3)));
233 #else
234 sds sdscatprintf(sds s, const char *fmt, ...);
235 #endif
236
237 sds sdscatfmt(sds s, char const *fmt, ...);
238 sds sdstrim(sds s, const char *cset);
239 void sdsrange(sds s, int start, int end);
240 void sdsupdatelen(sds s);
241 void sdsclear(sds s);
242 int sdscmp(const sds s1, const sds s2);
243 sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
244 void sdsfreesplitres(sds *tokens, int count);
245 void sdstolower(sds s);
246 void sdstoupper(sds s);
247 sds sdsfromlonglong(long long value);
248 sds sdscatrepr(sds s, const char *p, size_t len);
249 sds *sdssplitargs(const char *line, int *argc);
250 sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
251 sds sdsjoin(char **argv, int argc, char *sep);
252 sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
253
254 /* Low level functions exposed to the user API */
255 sds sdsMakeRoomFor(sds s, size_t addlen);
256 void sdsIncrLen(sds s, int incr);
257 sds sdsRemoveFreeSpace(sds s);
258 size_t sdsAllocSize(sds s);
259 void *sdsAllocPtr(sds s);
260
261 /* Export the allocator used by SDS to the program using SDS.
262 * Sometimes the program SDS is linked to, may use a different set of
263 * allocators, but may want to allocate or free things that SDS will
264 * respectively free or allocate. */
265 void *sds_malloc(size_t size);
266 void *sds_realloc(void *ptr, size_t size);
267 void sds_free(void *ptr);
268
269 #ifdef REDIS_TEST
270 int sdsTest(int argc, char *argv[]);
271 #endif
272
273 #endif
274