2 * string-icalls.c: String internal calls for the corlib
5 * Patrik Torstensson (patrik.torstensson@labs2.com)
6 * Duncan Mak (duncan@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
16 #include "mono/utils/mono-membar.h"
17 #include <mono/metadata/string-icalls.h>
18 #include <mono/metadata/class-internals.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/object.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/debug-helpers.h>
26 /* Internal helper methods */
29 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
31 /* This function is redirected to String.CreateString ()
32 by mono_marshal_get_native_wrapper () */
34 ves_icall_System_String_ctor_RedirectToCreateString (void)
36 g_assert_not_reached ();
40 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
55 insert = mono_string_chars(separator);
56 insertlen = mono_string_length(separator);
59 for (pos = sindex; pos != sindex + count; pos++) {
60 current = mono_array_get (value, MonoString *, pos);
62 length += mono_string_length (current);
64 if (pos < sindex + count - 1)
68 ret = mono_string_new_size( mono_domain_get (), length);
69 dest = mono_string_chars(ret);
72 for (pos = sindex; pos != sindex + count; pos++) {
73 current = mono_array_get (value, MonoString *, pos);
74 if (current != NULL) {
75 src = mono_string_chars (current);
76 srclen = mono_string_length (current);
78 memcpy (dest + destpos, src, srclen * sizeof(gunichar2));
82 if (pos < sindex + count - 1) {
83 memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
92 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
94 gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
95 gunichar2 *src = mono_string_chars(me);
99 memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
102 /* System.StringSplitOptions */
104 STRINGSPLITOPTIONS_NONE = 0,
105 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
106 } StringSplitOptions;
109 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
111 static MonoClass *String_array;
115 gint32 arrsize, srcsize, splitsize;
116 gint32 i, lastpos, arrpos;
120 gunichar2 *tmpstrptr;
122 remempty = options & STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES;
123 src = mono_string_chars (me);
124 srcsize = mono_string_length (me);
125 arrsize = mono_array_length (separator);
128 MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
129 mono_memory_barrier ();
130 String_array = klass;
134 /* Count the number of elements we will return. Note that this operation
135 * guarantees that we will return exactly splitsize elements, and we will
136 * have enough data to fill each. This allows us to skip some checks later on.
139 for (i = 0; i != srcsize && splitsize < count; i++) {
140 if (string_icall_is_in_array (separator, arrsize, src [i]))
143 } else if (count > 1) {
144 /* Require pattern "Nondelim + Delim + Nondelim" to increment counter.
145 * Lastpos != 0 means first nondelim found.
146 * Flag = 0 means last char was delim.
147 * Efficient, though perhaps confusing.
151 for (i = 0; i != srcsize && splitsize < count; i++) {
152 if (string_icall_is_in_array (separator, arrsize, src [i])) {
154 } else if (flag == 0) {
162 /* Nothing but separators */
164 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 0);
169 /* if no split chars found return the string */
170 if (splitsize == 1) {
171 if (remempty == 0 || count == 1) {
172 /* Copy the whole string */
173 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
174 mono_array_setref (retarr, 0, me);
176 /* otherwise we have to filter out leading & trailing delims */
178 /* find first non-delim char */
179 for (; srcsize != 0; srcsize--, src++) {
180 if (!string_icall_is_in_array (separator, arrsize, src [0]))
183 /* find last non-delim char */
184 for (; srcsize != 0; srcsize--) {
185 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
188 tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
189 tmpstrptr = mono_string_chars (tmpstr);
191 memcpy (tmpstrptr, src, srcsize * sizeof (gunichar2));
192 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
193 mono_array_setref (retarr, 0, tmpstr);
201 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), splitsize);
203 for (i = 0; i != srcsize && arrpos != splitsize; i++) {
204 if (string_icall_is_in_array (separator, arrsize, src [i])) {
206 if (lastpos != i || remempty == 0) {
207 tmpstrsize = i - lastpos;
208 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
209 tmpstrptr = mono_string_chars (tmpstr);
211 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
212 mono_array_setref (retarr, arrpos, tmpstr);
215 if (arrpos == splitsize - 1) {
216 /* Shortcut the last array element */
220 /* Search for non-delim starting char (guaranteed to find one) Note that loop
221 * condition is only there for safety. It will never actually terminate the loop. */
222 for (; lastpos != srcsize ; lastpos++) {
223 if (!string_icall_is_in_array (separator, arrsize, src [lastpos]))
226 if (count > splitsize) {
227 /* Since we have fewer results than our limit, we must remove
228 * trailing delimiters as well.
230 for (; srcsize != lastpos + 1 ; srcsize--) {
231 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
237 tmpstrsize = srcsize - lastpos;
238 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
239 tmpstrptr = mono_string_chars (tmpstr);
241 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
242 mono_array_setref (retarr, arrpos, tmpstr);
244 /* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
256 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
261 for (arrpos = 0; arrpos != arraylength; arrpos++) {
262 cmpchar = mono_array_get(chars, gunichar2, arrpos);
271 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
274 gunichar2 *src, *dest;
275 gint32 srclen, newlen, arrlen;
276 gint32 i, lenfirst, lenlast;
280 srclen = mono_string_length(me);
281 src = mono_string_chars(me);
282 arrlen = mono_array_length(chars);
287 if (0 == typ || 1 == typ) {
288 for (i = 0; i != srclen; i++) {
289 if (string_icall_is_in_array(chars, arrlen, src[i]))
296 if (0 == typ || 2 == typ) {
297 for (i = srclen - 1; i > lenfirst - 1; i--) {
298 if (string_icall_is_in_array(chars, arrlen, src[i]))
305 newlen = srclen - lenfirst - lenlast;
306 if (newlen == srclen)
309 ret = mono_string_new_size( mono_domain_get (), newlen);
310 dest = mono_string_chars(ret);
312 memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
318 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
327 arraysize = mono_array_length(anyOf);
328 src = mono_string_chars(me);
330 for (pos = sindex; pos > sindex - count; pos--) {
331 for (loop = 0; loop != arraysize; loop++)
332 if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
340 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
351 srclen = mono_string_length(me);
352 src = mono_string_chars(me);
354 ret = mono_string_new_size( mono_domain_get (), width);
355 dest = mono_string_chars(ret);
356 fillcount = width - srclen;
359 memcpy(dest, src, srclen * sizeof(gunichar2));
360 for (i = srclen; i != width; i++)
367 for (i = 0; i != fillcount; i++)
370 memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
376 ves_icall_System_String_InternalAllocateStr (gint32 length)
380 return mono_string_new_size(mono_domain_get (), length);
384 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
391 srcptr = mono_string_chars (src);
392 destptr = mono_string_chars (dest);
394 g_memmove (destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
398 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
405 srcptr = mono_string_chars (src);
406 destptr = mono_string_chars (dest);
407 g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
411 ves_icall_System_String_InternalStrcpy_Chars (MonoString *dest, gint32 destPos, MonoArray *src)
418 srcptr = mono_array_addr (src, gunichar2, 0);
419 destptr = mono_string_chars (dest);
421 g_memmove (destptr + destPos, srcptr, mono_array_length (src) * sizeof(gunichar2));
425 ves_icall_System_String_InternalStrcpy_CharsN (MonoString *dest, gint32 destPos, MonoArray *src, gint32 startPos, gint32 count)
432 srcptr = mono_array_addr (src, gunichar2, 0);
433 destptr = mono_string_chars (dest);
435 g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
439 ves_icall_System_String_InternalIntern (MonoString *str)
443 return mono_string_intern(str);
447 ves_icall_System_String_InternalIsInterned (MonoString *str)
451 return mono_string_is_interned(str);
455 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
459 if ((idx < 0) || (idx >= mono_string_length (me)))
460 mono_raise_exception (mono_get_exception_index_out_of_range ());
461 return mono_string_chars(me)[idx];