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 ();
39 /* System.StringSplitOptions */
41 STRINGSPLITOPTIONS_NONE
= 0,
42 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES
= 1
46 ves_icall_System_String_InternalSplit (MonoString
*me
, MonoArray
*separator
, gint32 count
, gint32 options
)
48 static MonoClass
*String_array
;
52 gint32 arrsize
, srcsize
, splitsize
;
53 gint32 i
, lastpos
, arrpos
;
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
);
65 MonoClass
*klass
= mono_array_class_get (mono_get_string_class (), 1);
66 mono_memory_barrier ();
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.
76 for (i
= 0; i
!= srcsize
&& splitsize
< count
; i
++) {
77 if (string_icall_is_in_array (separator
, arrsize
, src
[i
]))
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.
88 for (i
= 0; i
!= srcsize
&& splitsize
< count
; i
++) {
89 if (string_icall_is_in_array (separator
, arrsize
, src
[i
])) {
91 } else if (flag
== 0) {
99 /* Nothing but separators */
101 retarr
= mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array
), 0);
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
);
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]))
120 /* find last non-delim char */
121 for (; srcsize
!= 0; srcsize
--) {
122 if (!string_icall_is_in_array (separator
, arrsize
, src
[srcsize
- 1]))
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
);
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
);
152 if (arrpos
== splitsize
- 1) {
153 /* Shortcut the last array element */
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
]))
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]))
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. */
193 string_icall_is_in_array (MonoArray
*chars
, gint32 arraylength
, gunichar2 chr
)
198 for (arrpos
= 0; arrpos
!= arraylength
; arrpos
++) {
199 cmpchar
= mono_array_get(chars
, gunichar2
, arrpos
);
208 ves_icall_System_String_InternalAllocateStr (gint32 length
)
212 return mono_string_new_size(mono_domain_get (), length
);
216 ves_icall_System_String_InternalIntern (MonoString
*str
)
220 return mono_string_intern(str
);
224 ves_icall_System_String_InternalIsInterned (MonoString
*str
)
228 return mono_string_is_interned(str
);