2010-05-13 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / string-icalls.c
blob6dd333fb7bda71dc7621253f3e1cfe62c37da0c9
1 /*
2 * string-icalls.c: String internal calls for the corlib
4 * Author:
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)
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>
29 /* Internal helper methods */
31 static gboolean
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 () */
36 void
37 ves_icall_System_String_ctor_RedirectToCreateString (void)
39 g_assert_not_reached ();
42 /* System.StringSplitOptions */
43 typedef enum {
44 STRINGSPLITOPTIONS_NONE = 0,
45 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
46 } StringSplitOptions;
48 MonoArray *
49 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
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;
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);
67 if (!String_array) {
68 MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
69 mono_memory_barrier ();
70 String_array = klass;
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.
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++;
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.
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;
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;
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 */
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;
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;
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);
135 return retarr;
138 lastpos = 0;
139 arrpos = 0;
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);
153 arrpos++;
155 if (arrpos == splitsize - 1) {
156 /* Shortcut the last array element */
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;
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]))
172 break;
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. */
185 break;
188 lastpos = i + 1;
192 return retarr;
195 static gboolean
196 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
198 gunichar2 cmpchar;
199 gint32 arrpos;
201 for (arrpos = 0; arrpos != arraylength; arrpos++) {
202 cmpchar = mono_array_get(chars, gunichar2, arrpos);
203 if (cmpchar == chr)
204 return TRUE;
207 return FALSE;
210 MonoString *
211 ves_icall_System_String_InternalAllocateStr (gint32 length)
213 return mono_string_new_size(mono_domain_get (), length);
216 MonoString *
217 ves_icall_System_String_InternalIntern (MonoString *str)
219 MONO_ARCH_SAVE_REGS;
221 return mono_string_intern(str);
224 MonoString *
225 ves_icall_System_String_InternalIsInterned (MonoString *str)
227 MONO_ARCH_SAVE_REGS;
229 return mono_string_is_interned(str);
233 ves_icall_System_String_GetLOSLimit (void)
235 #ifdef HAVE_SGEN_GC
236 int limit = mono_gc_get_los_limit ();
238 return (limit - 2 - sizeof (MonoString)) / 2;
239 #else
240 return G_MAXINT;
241 #endif