2009-12-01 Jb Evain <jbevain@novell.com>
[mono.git] / mono / metadata / string-icalls.c
blob60675e38caa8434bf3fbe87730b153b740d575b8
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>
26 /* Internal helper methods */
28 static gboolean
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 () */
33 void
34 ves_icall_System_String_ctor_RedirectToCreateString (void)
36 g_assert_not_reached ();
39 /* System.StringSplitOptions */
40 typedef enum {
41 STRINGSPLITOPTIONS_NONE = 0,
42 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
43 } StringSplitOptions;
45 MonoArray *
46 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
48 static MonoClass *String_array;
49 MonoString * tmpstr;
50 MonoArray * retarr;
51 gunichar2 *src;
52 gint32 arrsize, srcsize, splitsize;
53 gint32 i, lastpos, arrpos;
54 gint32 tmpstrsize;
55 gint32 remempty;
56 gint32 flag;
57 gunichar2 *tmpstrptr;
59 remempty = options & STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES;
60 src = mono_string_chars (me);
61 srcsize = mono_string_length (me);
62 arrsize = mono_array_length (separator);
64 if (!String_array) {
65 MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
66 mono_memory_barrier ();
67 String_array = klass;
70 splitsize = 1;
71 /* Count the number of elements we will return. Note that this operation
72 * guarantees that we will return exactly splitsize elements, and we will
73 * have enough data to fill each. This allows us to skip some checks later on.
75 if (remempty == 0) {
76 for (i = 0; i != srcsize && splitsize < count; i++) {
77 if (string_icall_is_in_array (separator, arrsize, src [i]))
78 splitsize++;
80 } else if (count > 1) {
81 /* Require pattern "Nondelim + Delim + Nondelim" to increment counter.
82 * Lastpos != 0 means first nondelim found.
83 * Flag = 0 means last char was delim.
84 * Efficient, though perhaps confusing.
86 lastpos = 0;
87 flag = 0;
88 for (i = 0; i != srcsize && splitsize < count; i++) {
89 if (string_icall_is_in_array (separator, arrsize, src [i])) {
90 flag = 0;
91 } else if (flag == 0) {
92 if (lastpos == 1)
93 splitsize++;
94 flag = 1;
95 lastpos = 1;
99 /* Nothing but separators */
100 if (lastpos == 0) {
101 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 0);
102 return retarr;
106 /* if no split chars found return the string */
107 if (splitsize == 1) {
108 if (remempty == 0 || count == 1) {
109 /* Copy the whole string */
110 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
111 mono_array_setref (retarr, 0, me);
112 } else {
113 /* otherwise we have to filter out leading & trailing delims */
115 /* find first non-delim char */
116 for (; srcsize != 0; srcsize--, src++) {
117 if (!string_icall_is_in_array (separator, arrsize, src [0]))
118 break;
120 /* find last non-delim char */
121 for (; srcsize != 0; srcsize--) {
122 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
123 break;
125 tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
126 tmpstrptr = mono_string_chars (tmpstr);
128 memcpy (tmpstrptr, src, srcsize * sizeof (gunichar2));
129 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
130 mono_array_setref (retarr, 0, tmpstr);
132 return retarr;
135 lastpos = 0;
136 arrpos = 0;
138 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), splitsize);
140 for (i = 0; i != srcsize && arrpos != splitsize; i++) {
141 if (string_icall_is_in_array (separator, arrsize, src [i])) {
143 if (lastpos != i || remempty == 0) {
144 tmpstrsize = i - lastpos;
145 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
146 tmpstrptr = mono_string_chars (tmpstr);
148 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
149 mono_array_setref (retarr, arrpos, tmpstr);
150 arrpos++;
152 if (arrpos == splitsize - 1) {
153 /* Shortcut the last array element */
155 lastpos = i + 1;
156 if (remempty != 0) {
157 /* Search for non-delim starting char (guaranteed to find one) Note that loop
158 * condition is only there for safety. It will never actually terminate the loop. */
159 for (; lastpos != srcsize ; lastpos++) {
160 if (!string_icall_is_in_array (separator, arrsize, src [lastpos]))
161 break;
163 if (count > splitsize) {
164 /* Since we have fewer results than our limit, we must remove
165 * trailing delimiters as well.
167 for (; srcsize != lastpos + 1 ; srcsize--) {
168 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
169 break;
174 tmpstrsize = srcsize - lastpos;
175 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
176 tmpstrptr = mono_string_chars (tmpstr);
178 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
179 mono_array_setref (retarr, arrpos, tmpstr);
181 /* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
182 break;
185 lastpos = i + 1;
189 return retarr;
192 static gboolean
193 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
195 gunichar2 cmpchar;
196 gint32 arrpos;
198 for (arrpos = 0; arrpos != arraylength; arrpos++) {
199 cmpchar = mono_array_get(chars, gunichar2, arrpos);
200 if (cmpchar == chr)
201 return TRUE;
204 return FALSE;
207 MonoString *
208 ves_icall_System_String_InternalAllocateStr (gint32 length)
210 MONO_ARCH_SAVE_REGS;
212 return mono_string_new_size(mono_domain_get (), length);
215 MonoString *
216 ves_icall_System_String_InternalIntern (MonoString *str)
218 MONO_ARCH_SAVE_REGS;
220 return mono_string_intern(str);
223 MonoString *
224 ves_icall_System_String_InternalIsInterned (MonoString *str)
226 MONO_ARCH_SAVE_REGS;
228 return mono_string_is_interned(str);