[threadpool] fixes for epoll.
[mono.git] / mono / metadata / string-icalls.c
1 /*
2  * string-icalls.c: String internal calls for the corlib
3  *
4  * Author:
5  *   Patrik Torstensson (patrik.torstensson@labs2.com)
6  *   Duncan Mak  (duncan@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  */
11 #include <config.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <signal.h>
15 #include <string.h>
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>
28
29 /* Internal helper methods */
30
31 static gboolean
32 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
33
34 /* This function is redirected to String.CreateString ()
35    by mono_marshal_get_native_wrapper () */
36 void
37 ves_icall_System_String_ctor_RedirectToCreateString (void)
38 {
39         g_assert_not_reached ();
40 }
41
42 /* System.StringSplitOptions */
43 typedef enum {
44         STRINGSPLITOPTIONS_NONE = 0,
45         STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
46 } StringSplitOptions;
47
48 MonoArray * 
49 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
50 {
51         static MonoClass *String_array;
52         MonoString * tmpstr;
53         MonoArray * retarr;
54         gunichar2 *src;
55         gint32 arrsize, srcsize, splitsize;
56         gint32 i, lastpos, arrpos;
57         gint32 tmpstrsize;
58         gint32 remempty;
59         gint32 flag;
60         gunichar2 *tmpstrptr;
61
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);
66
67         if (!String_array) {
68                 MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
69                 mono_memory_barrier ();
70                 String_array = klass;
71         }
72
73         splitsize = 1;
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.
77          */
78         if (remempty == 0) {
79                 for (i = 0; i != srcsize && splitsize < count; i++) {
80                         if (string_icall_is_in_array (separator, arrsize, src [i]))
81                                 splitsize++;
82                 }
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.
88                  */
89                 lastpos = 0;
90                 flag = 0;
91                 for (i = 0; i != srcsize && splitsize < count; i++) {
92                         if (string_icall_is_in_array (separator, arrsize, src [i])) {
93                                 flag = 0;
94                         } else if (flag == 0) {
95                                 if (lastpos == 1)
96                                         splitsize++;
97                                 flag = 1;
98                                 lastpos = 1;
99                         }
100                 }
101
102                 /* Nothing but separators */
103                 if (lastpos == 0) {
104                         retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 0);
105                         return retarr;
106                 }
107         }
108
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);
115                 } else {
116                         /* otherwise we have to filter out leading & trailing delims */
117
118                         /* find first non-delim char */
119                         for (; srcsize != 0; srcsize--, src++) {
120                                 if (!string_icall_is_in_array (separator, arrsize, src [0]))
121                                         break;
122                         }
123                         /* find last non-delim char */
124                         for (; srcsize != 0; srcsize--) {
125                                 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
126                                         break;
127                         }
128                         tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
129                         tmpstrptr = mono_string_chars (tmpstr);
130
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);
134                 }
135                 return retarr;
136         }
137
138         lastpos = 0;
139         arrpos = 0;
140         
141         retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), splitsize);
142
143         for (i = 0; i != srcsize && arrpos != splitsize; i++) {
144                 if (string_icall_is_in_array (separator, arrsize, src [i])) {
145                         
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);
150
151                                 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
152                                 mono_array_setref (retarr, arrpos, tmpstr);
153                                 arrpos++;
154
155                                 if (arrpos == splitsize - 1) {
156                                         /* Shortcut the last array element */
157
158                                         lastpos = i + 1;
159                                         if (remempty != 0) {
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])) 
164                                                                 break;
165                                                 }
166                                                 if (count > splitsize) {
167                                                         /* Since we have fewer results than our limit, we must remove
168                                                          * trailing delimiters as well. 
169                                                          */
170                                                         for (; srcsize != lastpos + 1 ; srcsize--) {
171                                                                 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1])) 
172                                                                         break;
173                                                         }
174                                                 }
175                                         }
176
177                                         tmpstrsize = srcsize - lastpos;
178                                         tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
179                                         tmpstrptr = mono_string_chars (tmpstr);
180
181                                         memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
182                                         mono_array_setref (retarr, arrpos, tmpstr);
183
184                                         /* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
185                                         break;
186                                 }
187                         }
188                         lastpos = i + 1;
189                 }
190         }
191
192         return retarr;
193 }
194
195 static gboolean
196 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
197 {
198         gunichar2 cmpchar;
199         gint32 arrpos;
200
201         for (arrpos = 0; arrpos != arraylength; arrpos++) {
202                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
203                 if (cmpchar == chr)
204                         return TRUE;
205         }
206         
207         return FALSE;
208 }
209
210 MonoString *
211 ves_icall_System_String_InternalAllocateStr (gint32 length)
212 {
213         return mono_string_new_size(mono_domain_get (), length);
214 }
215
216 MonoString  *
217 ves_icall_System_String_InternalIntern (MonoString *str)
218 {
219         MonoString *res;
220         MONO_ARCH_SAVE_REGS;
221
222         res = mono_string_intern(str);
223         if (!res)
224                 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
225         return res;
226 }
227
228 MonoString * 
229 ves_icall_System_String_InternalIsInterned (MonoString *str)
230 {
231         MONO_ARCH_SAVE_REGS;
232
233         return mono_string_is_interned(str);
234 }
235
236 int
237 ves_icall_System_String_GetLOSLimit (void)
238 {
239 #ifdef HAVE_SGEN_GC
240         int limit = mono_gc_get_los_limit ();
241
242         return (limit - 2 - sizeof (MonoString)) / 2;
243 #else
244         return G_MAXINT;
245 #endif
246 }