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>
25 #include <mono/metadata/profiler.h>
26 #include <mono/metadata/profiler-private.h>
27 #include <mono/metadata/gc-internal.h>
29 /* Internal helper methods */
32 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
34 /* This function is redirected to String.CreateString ()
35 by mono_marshal_get_native_wrapper () */
37 ves_icall_System_String_ctor_RedirectToCreateString (void)
39 g_assert_not_reached ();
42 /* System.StringSplitOptions */
44 STRINGSPLITOPTIONS_NONE = 0,
45 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
49 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
51 static MonoClass *String_array;
55 gint32 arrsize, srcsize, splitsize;
56 gint32 i, lastpos, arrpos;
62 remempty = options & STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES;
63 src = mono_string_chars (me);
64 srcsize = mono_string_length (me);
65 arrsize = mono_array_length (separator);
68 MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
69 mono_memory_barrier ();
74 /* Count the number of elements we will return. Note that this operation
75 * guarantees that we will return exactly splitsize elements, and we will
76 * have enough data to fill each. This allows us to skip some checks later on.
79 for (i = 0; i != srcsize && splitsize < count; i++) {
80 if (string_icall_is_in_array (separator, arrsize, src [i]))
83 } else if (count > 1) {
84 /* Require pattern "Nondelim + Delim + Nondelim" to increment counter.
85 * Lastpos != 0 means first nondelim found.
86 * Flag = 0 means last char was delim.
87 * Efficient, though perhaps confusing.
91 for (i = 0; i != srcsize && splitsize < count; i++) {
92 if (string_icall_is_in_array (separator, arrsize, src [i])) {
94 } else if (flag == 0) {
102 /* Nothing but separators */
104 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 0);
109 /* if no split chars found return the string */
110 if (splitsize == 1) {
111 if (remempty == 0 || count == 1) {
112 /* Copy the whole string */
113 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
114 mono_array_setref (retarr, 0, me);
116 /* otherwise we have to filter out leading & trailing delims */
118 /* find first non-delim char */
119 for (; srcsize != 0; srcsize--, src++) {
120 if (!string_icall_is_in_array (separator, arrsize, src [0]))
123 /* find last non-delim char */
124 for (; srcsize != 0; srcsize--) {
125 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
128 tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
129 tmpstrptr = mono_string_chars (tmpstr);
131 memcpy (tmpstrptr, src, srcsize * sizeof (gunichar2));
132 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
133 mono_array_setref (retarr, 0, tmpstr);
141 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), splitsize);
143 for (i = 0; i != srcsize && arrpos != splitsize; i++) {
144 if (string_icall_is_in_array (separator, arrsize, src [i])) {
146 if (lastpos != i || remempty == 0) {
147 tmpstrsize = i - lastpos;
148 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
149 tmpstrptr = mono_string_chars (tmpstr);
151 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
152 mono_array_setref (retarr, arrpos, tmpstr);
155 if (arrpos == splitsize - 1) {
156 /* Shortcut the last array element */
160 /* Search for non-delim starting char (guaranteed to find one) Note that loop
161 * condition is only there for safety. It will never actually terminate the loop. */
162 for (; lastpos != srcsize ; lastpos++) {
163 if (!string_icall_is_in_array (separator, arrsize, src [lastpos]))
166 if (count > splitsize) {
167 /* Since we have fewer results than our limit, we must remove
168 * trailing delimiters as well.
170 for (; srcsize != lastpos + 1 ; srcsize--) {
171 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
177 tmpstrsize = srcsize - lastpos;
178 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
179 tmpstrptr = mono_string_chars (tmpstr);
181 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
182 mono_array_setref (retarr, arrpos, tmpstr);
184 /* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
196 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
201 for (arrpos = 0; arrpos != arraylength; arrpos++) {
202 cmpchar = mono_array_get(chars, gunichar2, arrpos);
211 ves_icall_System_String_InternalAllocateStr (gint32 length)
213 return mono_string_new_size(mono_domain_get (), length);
217 ves_icall_System_String_InternalIntern (MonoString *str)
222 res = mono_string_intern(str);
224 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
229 ves_icall_System_String_InternalIsInterned (MonoString *str)
233 return mono_string_is_interned(str);
237 ves_icall_System_String_GetLOSLimit (void)
240 int limit = mono_gc_get_los_limit ();
242 return (limit - 2 - sizeof (MonoString)) / 2;