2 * string-icalls.c: String internal calls for the corlib
5 * Patrik Torstensson (patrik.torstensson@labs2.com)
6 * Duncan Mak (duncan@ximian.com)
8 * (C) 2001 Ximian, Inc.
15 #include <mono/metadata/string-icalls.h>
16 #include <mono/metadata/class-internals.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/loader.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/debug-helpers.h>
24 /* Internal helper methods */
27 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
29 /* This function is redirected to String.CreateString ()
30 by mono_marshal_get_native_wrapper () */
32 ves_icall_System_String_ctor_RedirectToCreateString (void)
34 g_assert_not_reached ();
38 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
53 insert = mono_string_chars(separator);
54 insertlen = mono_string_length(separator);
57 for (pos = sindex; pos != sindex + count; pos++) {
58 current = mono_array_get (value, MonoString *, pos);
60 length += mono_string_length (current);
62 if (pos < sindex + count - 1)
66 ret = mono_string_new_size( mono_domain_get (), length);
67 dest = mono_string_chars(ret);
70 for (pos = sindex; pos != sindex + count; pos++) {
71 current = mono_array_get (value, MonoString *, pos);
72 if (current != NULL) {
73 src = mono_string_chars (current);
74 srclen = mono_string_length (current);
76 memcpy (dest + destpos, src, srclen * sizeof(gunichar2));
80 if (pos < sindex + count - 1) {
81 memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
90 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
92 gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
93 gunichar2 *src = mono_string_chars(me);
97 memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
100 /* System.StringSplitOptions */
102 STRINGSPLITOPTIONS_NONE = 0,
103 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
104 } StringSplitOptions;
107 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
112 gint32 arrsize, srcsize, splitsize;
113 gint32 i, lastpos, arrpos;
117 gunichar2 *tmpstrptr;
119 remempty = options & STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES;
120 src = mono_string_chars (me);
121 srcsize = mono_string_length (me);
122 arrsize = mono_array_length (separator);
125 /* Count the number of elements we will return. Note that this operation
126 * guarantees that we will return exactly splitsize elements, and we will
127 * have enough data to fill each. This allows us to skip some checks later on.
130 for (i = 0; i != srcsize && splitsize < count; i++) {
131 if (string_icall_is_in_array (separator, arrsize, src [i]))
134 } else if (count > 1) {
135 /* Require pattern "Nondelim + Delim + Nondelim" to increment counter.
136 * Lastpos != 0 means first nondelim found.
137 * Flag = 0 means last char was delim.
138 * Efficient, though perhaps confusing.
142 for (i = 0; i != srcsize && splitsize < count; i++) {
143 if (string_icall_is_in_array (separator, arrsize, src [i])) {
145 } else if (flag == 0) {
153 /* Nothing but separators */
155 retarr = mono_array_new (mono_domain_get (), mono_get_string_class (), 0);
160 /* if no split chars found return the string */
161 if (splitsize == 1) {
162 if (remempty == 0 || count == 1) {
163 /* Copy the whole string */
164 retarr = mono_array_new (mono_domain_get (), mono_get_string_class (), 1);
165 mono_array_setref (retarr, 0, me);
167 /* otherwise we have to filter out leading & trailing delims */
169 /* find first non-delim char */
170 for (; srcsize != 0; srcsize--, src++) {
171 if (!string_icall_is_in_array (separator, arrsize, src [0]))
174 /* find last non-delim char */
175 for (; srcsize != 0; srcsize--) {
176 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
179 tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
180 tmpstrptr = mono_string_chars (tmpstr);
182 memcpy (tmpstrptr, src, srcsize * sizeof (gunichar2));
183 retarr = mono_array_new (mono_domain_get (), mono_get_string_class (), 1);
184 mono_array_setref (retarr, 0, tmpstr);
192 retarr = mono_array_new (mono_domain_get (), mono_get_string_class (), splitsize);
194 for (i = 0; i != srcsize && arrpos != splitsize; i++) {
195 if (string_icall_is_in_array (separator, arrsize, src [i])) {
197 if (lastpos != i || remempty == 0) {
198 tmpstrsize = i - lastpos;
199 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
200 tmpstrptr = mono_string_chars (tmpstr);
202 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
203 mono_array_setref (retarr, arrpos, tmpstr);
206 if (arrpos == splitsize - 1) {
207 /* Shortcut the last array element */
211 /* Search for non-delim starting char (guaranteed to find one) Note that loop
212 * condition is only there for safety. It will never actually terminate the loop. */
213 for (; lastpos != srcsize ; lastpos++) {
214 if (!string_icall_is_in_array (separator, arrsize, src [lastpos]))
217 if (count > splitsize) {
218 /* Since we have fewer results than our limit, we must remove
219 * trailing delimiters as well.
221 for (; srcsize != lastpos + 1 ; srcsize--) {
222 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
228 tmpstrsize = srcsize - lastpos;
229 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
230 tmpstrptr = mono_string_chars (tmpstr);
232 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
233 mono_array_setref (retarr, arrpos, tmpstr);
235 /* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
247 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
252 for (arrpos = 0; arrpos != arraylength; arrpos++) {
253 cmpchar = mono_array_get(chars, gunichar2, arrpos);
262 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
265 gunichar2 *src, *dest;
266 gint32 srclen, newlen, arrlen;
267 gint32 i, lenfirst, lenlast;
271 srclen = mono_string_length(me);
272 src = mono_string_chars(me);
273 arrlen = mono_array_length(chars);
278 if (0 == typ || 1 == typ) {
279 for (i = 0; i != srclen; i++) {
280 if (string_icall_is_in_array(chars, arrlen, src[i]))
287 if (0 == typ || 2 == typ) {
288 for (i = srclen - 1; i > lenfirst - 1; i--) {
289 if (string_icall_is_in_array(chars, arrlen, src[i]))
296 newlen = srclen - lenfirst - lenlast;
297 if (newlen == srclen)
300 ret = mono_string_new_size( mono_domain_get (), newlen);
301 dest = mono_string_chars(ret);
303 memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
309 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
318 arraysize = mono_array_length(anyOf);
319 src = mono_string_chars(me);
321 for (pos = sindex; pos > sindex - count; pos--) {
322 for (loop = 0; loop != arraysize; loop++)
323 if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
331 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
342 srclen = mono_string_length(me);
343 src = mono_string_chars(me);
345 ret = mono_string_new_size( mono_domain_get (), width);
346 dest = mono_string_chars(ret);
347 fillcount = width - srclen;
350 memcpy(dest, src, srclen * sizeof(gunichar2));
351 for (i = srclen; i != width; i++)
358 for (i = 0; i != fillcount; i++)
361 memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
367 ves_icall_System_String_InternalAllocateStr (gint32 length)
371 return mono_string_new_size(mono_domain_get (), length);
375 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
382 srcptr = mono_string_chars (src);
383 destptr = mono_string_chars (dest);
385 g_memmove (destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
389 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
396 srcptr = mono_string_chars (src);
397 destptr = mono_string_chars (dest);
398 g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
402 ves_icall_System_String_InternalStrcpy_Chars (MonoString *dest, gint32 destPos, MonoArray *src)
409 srcptr = mono_array_addr (src, gunichar2, 0);
410 destptr = mono_string_chars (dest);
412 g_memmove (destptr + destPos, srcptr, mono_array_length (src) * sizeof(gunichar2));
416 ves_icall_System_String_InternalStrcpy_CharsN (MonoString *dest, gint32 destPos, MonoArray *src, gint32 startPos, gint32 count)
423 srcptr = mono_array_addr (src, gunichar2, 0);
424 destptr = mono_string_chars (dest);
426 g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
430 ves_icall_System_String_InternalIntern (MonoString *str)
434 return mono_string_intern(str);
438 ves_icall_System_String_InternalIsInterned (MonoString *str)
442 return mono_string_is_interned(str);
446 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
450 if ((idx < 0) || (idx >= mono_string_length (me)))
451 mono_raise_exception (mono_get_exception_index_out_of_range ());
452 return mono_string_chars(me)[idx];