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 HIREDIS_SDS_H |
34 | #define HIREDIS_SDS_H |
35 | |
36 | #define HI_SDS_MAX_PREALLOC (1024*1024) |
37 | #ifdef _MSC_VER |
38 | #define __attribute__(x) |
39 | typedef long long ssize_t; |
40 | #define SSIZE_MAX (LLONG_MAX >> 1) |
41 | #endif |
42 | |
43 | #include <sys/types.h> |
44 | #include <stdarg.h> |
45 | #include <stdint.h> |
46 | |
47 | typedef char *hisds; |
48 | |
49 | /* Note: sdshdr5 is never used, we just access the flags byte directly. |
50 | * However is here to document the layout of type 5 SDS strings. */ |
51 | struct __attribute__ ((__packed__)) hisdshdr5 { |
52 | unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ |
53 | char buf[]; |
54 | }; |
55 | struct __attribute__ ((__packed__)) hisdshdr8 { |
56 | uint8_t len; /* used */ |
57 | uint8_t alloc; /* excluding the header and null terminator */ |
58 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ |
59 | char buf[]; |
60 | }; |
61 | struct __attribute__ ((__packed__)) hisdshdr16 { |
62 | uint16_t len; /* used */ |
63 | uint16_t alloc; /* excluding the header and null terminator */ |
64 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ |
65 | char buf[]; |
66 | }; |
67 | struct __attribute__ ((__packed__)) hisdshdr32 { |
68 | uint32_t len; /* used */ |
69 | uint32_t alloc; /* excluding the header and null terminator */ |
70 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ |
71 | char buf[]; |
72 | }; |
73 | struct __attribute__ ((__packed__)) hisdshdr64 { |
74 | uint64_t len; /* used */ |
75 | uint64_t alloc; /* excluding the header and null terminator */ |
76 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ |
77 | char buf[]; |
78 | }; |
79 | |
80 | #define HI_SDS_TYPE_5 0 |
81 | #define HI_SDS_TYPE_8 1 |
82 | #define HI_SDS_TYPE_16 2 |
83 | #define HI_SDS_TYPE_32 3 |
84 | #define HI_SDS_TYPE_64 4 |
85 | #define HI_SDS_TYPE_MASK 7 |
86 | #define HI_SDS_TYPE_BITS 3 |
87 | #define HI_SDS_HDR_VAR(T,s) struct hisdshdr##T *sh = (struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T))); |
88 | #define HI_SDS_HDR(T,s) ((struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T)))) |
89 | #define HI_SDS_TYPE_5_LEN(f) ((f)>>HI_SDS_TYPE_BITS) |
90 | |
91 | static inline size_t hi_sdslen(const hisds s) { |
92 | unsigned char flags = s[-1]; |
93 | switch(flags & HI_SDS_TYPE_MASK) { |
94 | case HI_SDS_TYPE_5: |
95 | return HI_SDS_TYPE_5_LEN(flags); |
96 | case HI_SDS_TYPE_8: |
97 | return HI_SDS_HDR(8,s)->len; |
98 | case HI_SDS_TYPE_16: |
99 | return HI_SDS_HDR(16,s)->len; |
100 | case HI_SDS_TYPE_32: |
101 | return HI_SDS_HDR(32,s)->len; |
102 | case HI_SDS_TYPE_64: |
103 | return HI_SDS_HDR(64,s)->len; |
104 | } |
105 | return 0; |
106 | } |
107 | |
108 | static inline size_t hi_sdsavail(const hisds s) { |
109 | unsigned char flags = s[-1]; |
110 | switch(flags&HI_SDS_TYPE_MASK) { |
111 | case HI_SDS_TYPE_5: { |
112 | return 0; |
113 | } |
114 | case HI_SDS_TYPE_8: { |
115 | HI_SDS_HDR_VAR(8,s); |
116 | return sh->alloc - sh->len; |
117 | } |
118 | case HI_SDS_TYPE_16: { |
119 | HI_SDS_HDR_VAR(16,s); |
120 | return sh->alloc - sh->len; |
121 | } |
122 | case HI_SDS_TYPE_32: { |
123 | HI_SDS_HDR_VAR(32,s); |
124 | return sh->alloc - sh->len; |
125 | } |
126 | case HI_SDS_TYPE_64: { |
127 | HI_SDS_HDR_VAR(64,s); |
128 | return sh->alloc - sh->len; |
129 | } |
130 | } |
131 | return 0; |
132 | } |
133 | |
134 | static inline void hi_sdssetlen(hisds s, size_t newlen) { |
135 | unsigned char flags = s[-1]; |
136 | switch(flags&HI_SDS_TYPE_MASK) { |
137 | case HI_SDS_TYPE_5: |
138 | { |
139 | unsigned char *fp = ((unsigned char*)s)-1; |
140 | *fp = (unsigned char)(HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS)); |
141 | } |
142 | break; |
143 | case HI_SDS_TYPE_8: |
144 | HI_SDS_HDR(8,s)->len = (uint8_t)newlen; |
145 | break; |
146 | case HI_SDS_TYPE_16: |
147 | HI_SDS_HDR(16,s)->len = (uint16_t)newlen; |
148 | break; |
149 | case HI_SDS_TYPE_32: |
150 | HI_SDS_HDR(32,s)->len = (uint32_t)newlen; |
151 | break; |
152 | case HI_SDS_TYPE_64: |
153 | HI_SDS_HDR(64,s)->len = (uint64_t)newlen; |
154 | break; |
155 | } |
156 | } |
157 | |
158 | static inline void hi_sdsinclen(hisds s, size_t inc) { |
159 | unsigned char flags = s[-1]; |
160 | switch(flags&HI_SDS_TYPE_MASK) { |
161 | case HI_SDS_TYPE_5: |
162 | { |
163 | unsigned char *fp = ((unsigned char*)s)-1; |
164 | unsigned char newlen = HI_SDS_TYPE_5_LEN(flags)+(unsigned char)inc; |
165 | *fp = HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS); |
166 | } |
167 | break; |
168 | case HI_SDS_TYPE_8: |
169 | HI_SDS_HDR(8,s)->len += (uint8_t)inc; |
170 | break; |
171 | case HI_SDS_TYPE_16: |
172 | HI_SDS_HDR(16,s)->len += (uint16_t)inc; |
173 | break; |
174 | case HI_SDS_TYPE_32: |
175 | HI_SDS_HDR(32,s)->len += (uint32_t)inc; |
176 | break; |
177 | case HI_SDS_TYPE_64: |
178 | HI_SDS_HDR(64,s)->len += (uint64_t)inc; |
179 | break; |
180 | } |
181 | } |
182 | |
183 | /* hi_sdsalloc() = hi_sdsavail() + hi_sdslen() */ |
184 | static inline size_t hi_sdsalloc(const hisds s) { |
185 | unsigned char flags = s[-1]; |
186 | switch(flags & HI_SDS_TYPE_MASK) { |
187 | case HI_SDS_TYPE_5: |
188 | return HI_SDS_TYPE_5_LEN(flags); |
189 | case HI_SDS_TYPE_8: |
190 | return HI_SDS_HDR(8,s)->alloc; |
191 | case HI_SDS_TYPE_16: |
192 | return HI_SDS_HDR(16,s)->alloc; |
193 | case HI_SDS_TYPE_32: |
194 | return HI_SDS_HDR(32,s)->alloc; |
195 | case HI_SDS_TYPE_64: |
196 | return HI_SDS_HDR(64,s)->alloc; |
197 | } |
198 | return 0; |
199 | } |
200 | |
201 | static inline void hi_sdssetalloc(hisds s, size_t newlen) { |
202 | unsigned char flags = s[-1]; |
203 | switch(flags&HI_SDS_TYPE_MASK) { |
204 | case HI_SDS_TYPE_5: |
205 | /* Nothing to do, this type has no total allocation info. */ |
206 | break; |
207 | case HI_SDS_TYPE_8: |
208 | HI_SDS_HDR(8,s)->alloc = (uint8_t)newlen; |
209 | break; |
210 | case HI_SDS_TYPE_16: |
211 | HI_SDS_HDR(16,s)->alloc = (uint16_t)newlen; |
212 | break; |
213 | case HI_SDS_TYPE_32: |
214 | HI_SDS_HDR(32,s)->alloc = (uint32_t)newlen; |
215 | break; |
216 | case HI_SDS_TYPE_64: |
217 | HI_SDS_HDR(64,s)->alloc = (uint64_t)newlen; |
218 | break; |
219 | } |
220 | } |
221 | |
222 | hisds hi_sdsnewlen(const void *init, size_t initlen); |
223 | hisds hi_sdsnew(const char *init); |
224 | hisds hi_sdsempty(void); |
225 | hisds hi_sdsdup(const hisds s); |
226 | void hi_sdsfree(hisds s); |
227 | hisds hi_sdsgrowzero(hisds s, size_t len); |
228 | hisds hi_sdscatlen(hisds s, const void *t, size_t len); |
229 | hisds hi_sdscat(hisds s, const char *t); |
230 | hisds hi_sdscatsds(hisds s, const hisds t); |
231 | hisds hi_sdscpylen(hisds s, const char *t, size_t len); |
232 | hisds hi_sdscpy(hisds s, const char *t); |
233 | |
234 | hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap); |
235 | #ifdef __GNUC__ |
236 | hisds hi_sdscatprintf(hisds s, const char *fmt, ...) |
237 | __attribute__((format(printf, 2, 3))); |
238 | #else |
239 | hisds hi_sdscatprintf(hisds s, const char *fmt, ...); |
240 | #endif |
241 | |
242 | hisds hi_sdscatfmt(hisds s, char const *fmt, ...); |
243 | hisds hi_sdstrim(hisds s, const char *cset); |
244 | int hi_sdsrange(hisds s, ssize_t start, ssize_t end); |
245 | void hi_sdsupdatelen(hisds s); |
246 | void hi_sdsclear(hisds s); |
247 | int hi_sdscmp(const hisds s1, const hisds s2); |
248 | hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); |
249 | void hi_sdsfreesplitres(hisds *tokens, int count); |
250 | void hi_sdstolower(hisds s); |
251 | void hi_sdstoupper(hisds s); |
252 | hisds hi_sdsfromlonglong(long long value); |
253 | hisds hi_sdscatrepr(hisds s, const char *p, size_t len); |
254 | hisds *hi_sdssplitargs(const char *line, int *argc); |
255 | hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen); |
256 | hisds hi_sdsjoin(char **argv, int argc, char *sep); |
257 | hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen); |
258 | |
259 | /* Low level functions exposed to the user API */ |
260 | hisds hi_sdsMakeRoomFor(hisds s, size_t addlen); |
261 | void hi_sdsIncrLen(hisds s, int incr); |
262 | hisds hi_sdsRemoveFreeSpace(hisds s); |
263 | size_t hi_sdsAllocSize(hisds s); |
264 | void *hi_sdsAllocPtr(hisds s); |
265 | |
266 | /* Export the allocator used by SDS to the program using SDS. |
267 | * Sometimes the program SDS is linked to, may use a different set of |
268 | * allocators, but may want to allocate or free things that SDS will |
269 | * respectively free or allocate. */ |
270 | void *hi_sds_malloc(size_t size); |
271 | void *hi_sds_realloc(void *ptr, size_t size); |
272 | void hi_sds_free(void *ptr); |
273 | |
274 | #ifdef REDIS_TEST |
275 | int hi_sdsTest(int argc, char *argv[]); |
276 | #endif |
277 | |
278 | #endif /* HIREDIS_SDS_H */ |
279 | |