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
)
221 return mono_string_intern(str
);
225 ves_icall_System_String_InternalIsInterned (MonoString
*str
)
229 return mono_string_is_interned(str
);
233 ves_icall_System_String_GetLOSLimit (void)
236 int limit
= mono_gc_get_los_limit ();
238 return (limit
- 2 - sizeof (MonoString
)) / 2;