summaryrefslogtreecommitdiffhomepage
path: root/cstring.h
blob: 42f2ea76e6e271f4352c41c2dba23a24b30518ff (plain)
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
// MIT License
//
// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#ifndef CSTRING__H__
#define CSTRING__H__

#include <malloc.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>

#include "cdef.h"

typedef struct CString {
    char* str;
} CString;


static size_t _cstring_null_rep[] = {0, 0, 0};
#define       _cstring_rep(cs)      (((size_t *) (cs).str) - 2)

#define cstring_initializer   {(char* ) (_cstring_null_rep + 2)}
#define cstring_size(cs)      ((size_t) _cstring_rep(cs)[0])
#define cstring_capacity(cs)  ((size_t) _cstring_rep(cs)[1])
#define cstring_npos          ((size_t) -1)


static inline void cstring_reserve(CString* self, size_t cap) {
    size_t len = cstring_size(*self), oldcap = cstring_capacity(*self);
    if (cap > oldcap) {
        size_t* rep = (size_t *) realloc(oldcap ? _cstring_rep(*self) : NULL, sizeof(size_t) * 2 + cap + 1);
        rep[0] = len;
        rep[1] = cap;
        self->str = (char* ) (rep + 2);
        self->str[len] = '\0';
    }
}

static inline void cstring_destroy(CString* self) {
    if (cstring_capacity(*self)) {
        free(_cstring_rep(*self));
    }
}

static inline CString cstring_init(void) {
    CString cs = cstring_initializer;
    return cs;
}

static inline CString cstring_makeN(const char* str, size_t len) {
    CString cs = cstring_initializer;
    if (len) {
        cstring_reserve(&cs, len);
        memcpy(cs.str, str, len);
        cs.str[ _cstring_rep(cs)[0] = len ] = '\0';
    }
    return cs;
}

static inline CString cstring_make(const char* str) {
    return cstring_makeN(str, strlen(str));
}

static inline CString cstring_makeCopy(CString cs) {
    return cstring_makeN(cs.str, cstring_size(cs));
}

static inline void cstring_clear(CString* self) {
    CString cs = cstring_initializer;
    cstring_destroy(self);
    *self = cs;
}

static inline CString* cstring_assignN(CString* self, const char* str, size_t len) {
    if (len) {
        cstring_reserve(self, len);
        memmove(self->str, str, len);
        self->str[_cstring_rep(*self)[0] = len] = '\0';
    }
    return self;
}

static inline CString* cstring_assign(CString* self, const char* str) {
    return cstring_assignN(self, str, strlen(str));
}

static inline CString* cstring_copy(CString* self, CString cs2) {
    return cstring_assignN(self, cs2.str, cstring_size(cs2));
}


static inline CString* cstring_appendN(CString* self, const char* str, size_t len) {
    if (len) {
        size_t oldlen = cstring_size(*self), newlen = oldlen + len;
        if (newlen > cstring_capacity(*self))
            cstring_reserve(self, newlen * 5 / 3);
        memmove(&self->str[oldlen], str, len);
        self->str[_cstring_rep(*self)[0] = newlen] = '\0';
    }
    return self;
}

static inline CString* cstring_append(CString* self, const char* str) {
    return cstring_appendN(self, str, strlen(str));
}
static inline CString* cstring_appendS(CString* self, CString cs2) {
    return cstring_appendN(self, cs2.str, cstring_size(cs2));
}


static inline void _cstring_internalMove(CString* self, size_t pos1, size_t pos2) {
    if (pos1 == pos2)
        return;
    size_t len = cstring_size(*self), newlen = len + pos2 - pos1;
    if (newlen > cstring_capacity(*self))
        cstring_reserve(self, newlen * 5 / 3);
    memmove(&self->str[pos2], &self->str[pos1], len - pos1);
    self->str[_cstring_rep(*self)[0] = newlen] = '\0';
}

static inline void cstring_insertN(CString* self, size_t pos, const char* str, size_t n) {
    char* xstr = (char *) memcpy(alloca(n), str, n);
    _cstring_internalMove(self, pos, pos + n);
    memcpy(&self->str[pos], xstr, n);
}

static inline void cstring_insert(CString* self, size_t pos, const char* str) {
    cstring_insertN(self, pos, str, strlen(str));
}

static inline void cstring_erase(CString* self, size_t pos, size_t n) {
    size_t len = cstring_size(*self);
    if (len) {
        memmove(&self->str[pos], &self->str[pos + n], len - (pos + n));
        self->str[_cstring_rep(*self)[0] -= n] = '\0';
    }
}

static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n);

static inline size_t cstring_replaceN(CString* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) {
    size_t pos2 = cstring_findN(*self, pos, s1, n1);
    if (pos2 == cstring_npos) return cstring_npos;
    char* xs2 = (char *) memcpy(alloca(n2), s2, n2);
    _cstring_internalMove(self, pos2 + n1, pos2 + n2);
    memcpy(&self->str[pos2], xs2, n2);
    return pos2;
}

static inline size_t cstring_replace(CString* self, size_t pos, const char* s1, const char* s2) {
    return cstring_replaceN(self, pos, s1, strlen(s1), s2, strlen(s2));
}


static inline char cstring_back(CString cs) {
    return cs.str[cstring_size(cs) - 1];
}

static inline CString* cstring_push(CString* self, char value) {
    return cstring_appendN(self, &value, 1);
}


static inline void cstring_pop(CString* self) {
    --_cstring_rep(*self)[0];
}

/* readonly */

static inline bool cstring_empty(CString cs) {
    return cstring_size(cs) == 0;
}

static inline bool cstring_equals(CString cs1, const char* str) {
    return strcmp(cs1.str, str) == 0;
}
static inline bool cstring_equalsS(CString cs1, CString cs2) {
    return strcmp(cs1.str, cs2.str) == 0;
}

static inline char* cstring_strnstr(CString cs, size_t pos, const char* needle, size_t n) {
    char *x = cs.str + pos, // haystack
         *z = cs.str + cstring_size(cs) - n + 1;
    if (x >= z)
        return NULL;
    ptrdiff_t sum = 0;
    const char *y = x, *p = needle, *q = needle + n;
    while (p != q)
        sum += *y++ - *p++;
    while (x != z) {
        if (sum == 0 && memcmp(x, needle, n) == 0)
            return x;
        sum += *y++ - *x++;
    }
    return NULL;
}

static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n) {
    char* res = cstring_strnstr(cs, pos, needle, n);
    return res ? res - cs.str : cstring_npos;
}

static inline size_t cstring_find(CString cs, size_t pos, const char* needle) {
    char* res = strstr(cs.str + pos, needle);
    return res ? res - cs.str : cstring_npos;
}

static inline char* cstring_splitFirst(const char* delimiters, CString cs) {
    return strtok(cs.str, delimiters);
}

static inline char* cstring_splitNext(const char* delimiters) {
    return strtok(NULL, delimiters);
}


// CVector / CMap API functions:

#define                cstring_getRaw(x) ((x).str)
static inline uint32_t cstring_hash(const char** str, size_t sz_ignored) { return cdef_murmurHash(*str, strlen(*str)); }
static inline int      cstring_compare(CString* self, const char** str, size_t sz_ignored) { return strcmp(self->str, *str); }


#endif