-
Notifications
You must be signed in to change notification settings - Fork 29
/
sds.c
392 lines (363 loc) · 11.4 KB
/
sds.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
/* SDSLib, A C dynamic strings library
*
* Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
//发生内存错误时终止程序
#define SDS_ABORT_ON_OOM
#include "sds.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "zmalloc.h"
//内存出错函数
static void sdsOomAbort(void) {
//发生内存错误时向标准输出设备输出出错信息
fprintf(stderr,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
abort();//出错时直接终止程序
}
//新建一个字符串,并将其初始化,初始化时,取init字符串中initlen个字符
sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
//创建字符串存储空间,多创建一个1,是因为C语言中的字符串
//均有一个\0结束符
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
#ifdef SDS_ABORT_ON_OOM
//如果内存分配失败的情况下,直接终止程序的运行
if (sh == NULL) sdsOomAbort();
#else
//如果内存分配失败的情况下,返回NULL
if (sh == NULL) return NULL;
#endif
//记录内存空间的实际使用量
sh->len = initlen;
//记录内存空间的余下多少
sh->free = 0;
if (initlen) {
//如果设置了init的情况下,复制initlen个字符
if (init) memcpy(sh->buf, init, initlen);
//否则将内存全部置为0
else memset(sh->buf,0,initlen);
}
//结尾字符,C语言中字符串均以\0结尾
sh->buf[initlen] = '\0';
return (char*)sh->buf;
}
//生成一个空字符串
sds sdsempty(void) {
return sdsnewlen("",0);
}
/*
* 生成一个新字符串
* init表字生成新字符串时要拷贝进来的东西
*/
sds sdsnew(const char *init) {
size_t initlen = (init == NULL) ? 0 : strlen(init);
return sdsnewlen(init, initlen);
}
/*
* 获取字符串的长度
* 字符串的长度是存放在sdshdr结构中的len里面
*/
size_t sdslen(const sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
return sh->len;
}
/*
* 对字符串进行复制
*/
sds sdsdup(const sds s) {
return sdsnewlen(s, sdslen(s));
}
/*
* 释放字符串
*/
void sdsfree(sds s) {
if (s == NULL) return;
zfree(s-sizeof(struct sdshdr));
}
/*
* 返回字符串中还有多少空间可以使用
*/
size_t sdsavail(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
return sh->free;
}
/*
* 更新字符串的长度
*/
void sdsupdatelen(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
int reallen = strlen(s);
sh->free += (sh->len-reallen);
sh->len = reallen;
}
/*
* 给字符串增加长度
*/
static sds sdsMakeRoomFor(sds s, size_t addlen) {
struct sdshdr *sh, *newsh;
size_t free = sdsavail(s);
size_t len, newlen;
//如果余下空间还足够的话
if (free >= addlen) return s;
len = sdslen(s);
sh = (void*) (s-(sizeof(struct sdshdr)));
newlen = (len+addlen)*2;
newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
//内存分配失败的情况下进行处理
#ifdef SDS_ABORT_ON_OOM
if (newsh == NULL) sdsOomAbort();
#else
if (newsh == NULL) return NULL;
#endif
//新的余下空间
newsh->free = newlen - len;
return newsh->buf;
}
//进行字符串的拼接操作
sds sdscatlen(sds s, void *t, size_t len) {
struct sdshdr *sh;
size_t curlen = sdslen(s);
s = sdsMakeRoomFor(s,len);
if (s == NULL) return NULL;
sh = (void*) (s-(sizeof(struct sdshdr)));
memcpy(s+curlen, t, len);
sh->len = curlen+len;
sh->free = sh->free-len;
s[curlen+len] = '\0';
return s;
}
//同样进行字符串的拼接操作
sds sdscat(sds s, char *t) {
return sdscatlen(s, t, strlen(t));
}
//进行字符串的copy,会覆盖掉原字符串
sds sdscpylen(sds s, char *t, size_t len) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
//字符串s代表的字符串的总共长度
size_t totlen = sh->free+sh->len;
if (totlen < len) {
s = sdsMakeRoomFor(s,len-totlen);
if (s == NULL) return NULL;
sh = (void*) (s-(sizeof(struct sdshdr)));
totlen = sh->free+sh->len;
}
memcpy(s, t, len);
s[len] = '\0';
sh->len = len;
sh->free = totlen-len;
return s;
}
//同样也是进行字符串的copy
//也会覆盖掉原字符串
sds sdscpy(sds s, char *t) {
return sdscpylen(s, t, strlen(t));
}
//格式化拼接字符串
sds sdscatprintf(sds s, const char *fmt, ...) {
va_list ap;
char *buf, *t;
size_t buflen = 32;
while(1) {
buf = zmalloc(buflen);
#ifdef SDS_ABORT_ON_OOM
if (buf == NULL) sdsOomAbort();
#else
if (buf == NULL) return NULL;
#endif
buf[buflen-2] = '\0';
//c语言中的可变参数的循环遍历
va_start(ap, fmt);
vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
if (buf[buflen-2] != '\0') {
zfree(buf);
buflen *= 2;
continue;
}
break;
}
//对字符串进行拼接
t = sdscat(s, buf);
zfree(buf);
return t;
}
//字符串中去掉首尾包含cset里的字符
sds sdstrim(sds s, const char *cset) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
char *start, *end, *sp, *ep;
size_t len;
//字符串的开始位置
sp = start = s;
//字符串的结束位置
ep = end = s+sdslen(s)-1;
//查看字符串cset中首次出现字符*sp的位置
while(sp <= end && strchr(cset, *sp)) sp++;
//查找字符串cset中首次出现字符*ep的位置
while(ep > start && strchr(cset, *ep)) ep--;
len = (sp > ep) ? 0 : ((ep-sp)+1);
//字符串的内存移动操作
if (sh->buf != sp) memmove(sh->buf, sp, len);
sh->buf[len] = '\0';
//字符串的余下空间增长
sh->free = sh->free+(sh->len-len);
sh->len = len;
return s;
}
//获取指定范围里的字符串
sds sdsrange(sds s, long start, long end) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
size_t newlen, len = sdslen(s);
if (len == 0) return s;
if (start < 0) {
start = len+start;
if (start < 0) start = 0;
}
if (end < 0) {
end = len+end;
if (end < 0) end = 0;
}
newlen = (start > end) ? 0 : (end-start)+1;
if (newlen != 0) {
if (start >= (signed)len) start = len-1;
if (end >= (signed)len) end = len-1;
newlen = (start > end) ? 0 : (end-start)+1;
} else {
start = 0;
}
if (start != 0) memmove(sh->buf, sh->buf+start, newlen);
sh->buf[newlen] = 0;
sh->free = sh->free+(sh->len-newlen);
sh->len = newlen;
return s;
}
//将字符串中的所有字符均转为小写的形式
void sdstolower(sds s) {
int len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
}
//将字符串中所有字符均转为大写的形式
void sdstoupper(sds s) {
int len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
}
//对两个字符串进行比较
int sdscmp(sds s1, sds s2) {
size_t l1, l2, minlen;
int cmp;
l1 = sdslen(s1);
l2 = sdslen(s2);
minlen = (l1 < l2) ? l1 : l2;
cmp = memcmp(s1,s2,minlen);
if (cmp == 0) return l1-l2;
return cmp;
}
/* Split 's' with separator in 'sep'. An array
* of sds strings is returned. *count will be set
* by reference to the number of tokens returned.
*
* On out of memory, zero length string, zero length
* separator, NULL is returned.
*
* Note that 'sep' is able to split a string using
* a multi-character separator. For example
* sdssplit("foo_-_bar","_-_"); will return two
* elements "foo" and "bar".
*
* This version of the function is binary-safe but
* requires length arguments. sdssplit() is just the
* same function but for zero-terminated strings.
*/
sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
int elements = 0, slots = 5, start = 0, j;
//开设5字节的内存空间
//实际开设时会开设6字节,具体可以参看zmallo.c里的源代码
sds *tokens = zmalloc(sizeof(sds)*slots);
#ifdef SDS_ABORT_ON_OOM
if (tokens == NULL) sdsOomAbort();
#endif
if (seplen < 1 || len < 0 || tokens == NULL) return NULL;
for (j = 0; j < (len-(seplen-1)); j++) {
/* make sure there is room for the next element and the final one */
if (slots < elements+2) {
sds *newtokens;
slots *= 2;
newtokens = zrealloc(tokens,sizeof(sds)*slots);
if (newtokens == NULL) {
#ifdef SDS_ABORT_ON_OOM
sdsOomAbort();
#else
goto cleanup;
#endif
}
tokens = newtokens;
}
/* search the separator */
if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
//计算分割符以前的字符串的长度
tokens[elements] = sdsnewlen(s+start,j-start);
if (tokens[elements] == NULL) {
#ifdef SDS_ABORT_ON_OOM
sdsOomAbort();//失败的情况下,如果定义了内存失败函数,将直接调用
#else
goto cleanup;//否则跳到cleanup函数,进行一个一个的释放
#endif
}
elements++;
start = j+seplen;
j = j+seplen-1; /* skip the separator */
}
}
/* Add the final element. We are sure there is room in the tokens array. */
//分割串里面的最后一个字符串
tokens[elements] = sdsnewlen(s+start,len-start);
if (tokens[elements] == NULL) {
#ifdef SDS_ABORT_ON_OOM
sdsOomAbort();
#else
goto cleanup;
#endif
}
elements++;
//传的是个引用,可以获取最终分割为多少个数组
*count = elements;
return tokens;
#ifndef SDS_ABORT_ON_OOM
//如果没有定义分配失败的情况下,内存操作函数
//将会一个一个的调用内存失败处理函数
cleanup:
{
int i;
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
zfree(tokens);
return NULL;
}
#endif
}