xref: /redis-3.2.3/src/sds.h (revision b9429fd8)
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