2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2017 Jason King
15 #include <sys/debug.h>
16 #include <sys/sysmacros.h>
19 #include "demangle_int.h"
21 #define STR_CHUNK_SZ (64U)
23 /* are we storing a reference vs. a dynamically allocated copy? */
24 #define IS_REF(s) ((s)->str_s != NULL && (s)->str_size == 0)
27 * Dynamically resizeable strings, with lazy allocation when initialized
28 * with a constant string value
30 * NOTE: these are not necessairly 0-terminated
32 * Additionally, these can store references instead of copies of strings
33 * (as indicated by the IS_REF() macro. However mutation may cause a
34 * string to convert from a refence to a dynamically allocated copy.
38 str_init(str_t
*restrict s
, sysdem_ops_t
*restrict ops
)
40 (void) memset(s
, 0, sizeof (*s
));
41 s
->str_ops
= (ops
!= NULL
) ? ops
: sysdem_ops_default
;
50 xfree(s
->str_ops
, s
->str_s
, s
->str_size
);
51 (void) memset(s
, 0, sizeof (*s
));
55 str_length(const str_t
*s
)
61 * store as a reference instead of a copy
62 * if len == 0, means store entire copy of 0 terminated string
65 str_set(str_t
*s
, const char *cstr
, size_t len
)
67 sysdem_ops_t
*ops
= s
->str_ops
;
71 s
->str_s
= (char *)cstr
;
72 s
->str_len
= (len
== 0 && cstr
!= NULL
) ? strlen(cstr
) : len
;
76 str_copy(const str_t
*src
, str_t
*dest
)
79 str_init(dest
, src
->str_ops
);
81 if (src
->str_len
== 0)
84 size_t len
= roundup(src
->str_len
, STR_CHUNK_SZ
);
85 dest
->str_s
= zalloc(src
->str_ops
, len
);
86 if (dest
->str_s
== NULL
)
89 (void) memcpy(dest
->str_s
, src
->str_s
, src
->str_len
);
90 dest
->str_len
= src
->str_len
;
97 * ensure s has at least amt bytes free, resizing if necessary
100 str_reserve(str_t
*s
, size_t amt
)
102 size_t newlen
= s
->str_len
+ amt
;
105 if (newlen
< s
->str_len
|| newlen
< amt
)
108 if ((amt
> 0) && (s
->str_len
+ amt
<= s
->str_size
))
111 size_t newsize
= roundup(newlen
, STR_CHUNK_SZ
);
115 temp
= zalloc(s
->str_ops
, newsize
);
119 (void) memcpy(temp
, s
->str_s
, s
->str_len
);
121 temp
= xrealloc(s
->str_ops
, s
->str_s
, s
->str_size
, newsize
);
127 s
->str_size
= newsize
;
132 /* append to s, cstrlen == 0 means entire length of string */
134 str_append(str_t
*s
, const char *cstr
, size_t cstrlen
)
136 if (cstr
!= NULL
&& cstrlen
== 0)
137 cstrlen
= strlen(cstr
);
140 .str_s
= (char *)cstr
,
142 .str_ops
= s
->str_ops
145 return (str_append_str(s
, &src
));
149 str_append_str(str_t
*dest
, const str_t
*src
)
151 /* empty string is a noop */
152 if (src
->str_s
== NULL
|| src
->str_len
== 0)
155 /* if src is a reference, we can just copy that */
156 if (dest
->str_s
== NULL
&& IS_REF(src
)) {
161 if (!str_reserve(dest
, src
->str_len
))
164 (void) memcpy(dest
->str_s
+ dest
->str_len
, src
->str_s
, src
->str_len
);
165 dest
->str_len
+= src
->str_len
;
170 str_append_c(str_t
*s
, char c
)
172 if (!str_reserve(s
, 1))
175 s
->str_s
[s
->str_len
++] = c
;
180 str_insert(str_t
*s
, size_t idx
, const char *cstr
, size_t cstrlen
)
186 cstrlen
= strlen(cstr
);
189 .str_s
= (char *)cstr
,
191 .str_ops
= s
->str_ops
,
195 return (str_insert_str(s
, idx
, &src
));
199 str_insert_str(str_t
*dest
, size_t idx
, const str_t
*src
)
201 ASSERT3U(idx
, <=, dest
->str_len
);
203 if (idx
== dest
->str_len
)
204 return (str_append_str(dest
, src
));
206 if (idx
== 0 && dest
->str_s
== NULL
&& IS_REF(src
)) {
207 sysdem_ops_t
*ops
= dest
->str_ops
;
213 if (!str_reserve(dest
, src
->str_len
))
217 * Shift the contents of dest over at the insertion point. Since
218 * src and dest ranges will overlap, and unlike some programmers,
219 * *I* can read man pages - memmove() is the appropriate function
222 (void) memmove(dest
->str_s
+ idx
+ src
->str_len
, dest
->str_s
+ idx
,
223 dest
->str_len
- idx
);
226 * However the content to insert does not overlap with the destination
227 * so memcpy() is fine here.
229 (void) memcpy(dest
->str_s
+ idx
, src
->str_s
, src
->str_len
);
230 dest
->str_len
+= src
->str_len
;
236 str_erase(str_t
*s
, size_t pos
, size_t len
)
238 ASSERT3U(pos
, <, s
->str_len
);
239 ASSERT3U(pos
+ len
, <=, s
->str_len
);
242 if (!str_reserve(s
, 0))
246 (void) memmove(s
->str_s
+ pos
, s
->str_s
+ pos
+ len
, s
->str_len
- len
);
252 str_pair_init(str_pair_t
*sp
, sysdem_ops_t
*ops
)
254 (void) memset(sp
, 0, sizeof (*sp
));
255 str_init(&sp
->strp_l
, ops
);
256 str_init(&sp
->strp_r
, ops
);
261 str_pair_fini(str_pair_t
*sp
)
263 str_fini(&sp
->strp_l
);
264 str_fini(&sp
->strp_r
);
267 /* combine left and right parts and put result into left part */
269 str_pair_merge(str_pair_t
*sp
)
271 /* if right side is empty, don't need to do anything */
272 if (str_length(&sp
->strp_r
) == 0)
275 /* if left side is empty, just move right to left */
276 if (str_length(&sp
->strp_l
) == 0) {
277 str_fini(&sp
->strp_l
);
278 sp
->strp_l
= sp
->strp_r
;
279 sp
->strp_r
.str_s
= NULL
;
280 sp
->strp_r
.str_len
= sp
->strp_r
.str_size
= 0;
284 if (!str_append_str(&sp
->strp_l
, &sp
->strp_r
))
287 str_fini(&sp
->strp_r
);
288 str_init(&sp
->strp_r
, sp
->strp_l
.str_ops
);
293 str_pair_copy(const str_pair_t
*src
, str_pair_t
*dest
)
295 boolean_t ok
= B_TRUE
;
297 ok
&= str_copy(&src
->strp_l
, &dest
->strp_l
);
298 ok
&= str_copy(&src
->strp_r
, &dest
->strp_r
);
301 str_fini(&dest
->strp_l
);
302 str_fini(&dest
->strp_r
);
310 str_pair_len(const str_pair_t
*sp
)
312 return (str_length(&sp
->strp_l
) + str_length(&sp
->strp_r
));