On 06/01/10 04:23, Vasily Chekalkin wrote:
Nick Wellnhofer wrote:
It seems that all ways to iterate over the characters in a UTF8 string
have quadratic running time. See the attached test. I would expect
that for keyed access and 'substr' but iterator access and 'split'
should have better performance. I had a look at the string iterator
PMC code and it doesn't use the iterators that the underlying string
API provides.
I can offer to write a patch to fix this if noone else is working on
this.
Good idea! Patches welcome!
Here is a preliminary patch.
I would also suggest to move the iterator function pointers from struct
string_iterator_t to struct encoding_t and introduce new macros similar
to ENCODING_ITER_INIT like I did in my patch. If that's OK I can convert
the rest of the string iterator users.
It would also be helpful to remove the const qualifier from the 'str'
member of struct string_iterator_t. Or is it important?
Nick
Index: src/pmc/stringiterator.pmc
===================================================================
--- src/pmc/stringiterator.pmc (revision 43399)
+++ src/pmc/stringiterator.pmc (working copy)
@@ -23,11 +23,10 @@
pmclass StringIterator auto_attrs extends Iterator {
- ATTR PMC *string; /* String to iterate over */
- ATTR INTVAL pos; /* Current position of iterator for forward
iterator */
- /* Previous position of iterator for reverse
iterator */
- ATTR INTVAL length; /* Length of C<string> */
- ATTR INTVAL reverse; /* Direction of iteration. 1 - for reverse
iteration */
+ ATTR PMC *string; /* String to iterate over */
+ ATTR String_iter iter; /* String iterator */
+ ATTR UINTVAL length; /* Length of C<string> */
+ ATTR INTVAL reverse; /* Direction of iteration. 1 - for reverse
iteration */
/*
@@ -39,7 +38,12 @@
*/
VTABLE void init_pmc(PMC *string) {
+ Parrot_StringIterator_attributes * const attrs =
+ PARROT_STRINGITERATOR(SELF);
+ STRING * const str_val = VTABLE_get_string(INTERP, string);
+
SET_ATTR_string(INTERP, SELF, string);
+ ENCODING_ITER_INIT(INTERP, str_val, &attrs->iter);
/* by default, iterate from start */
SELF.set_integer_native(ITERATE_FROM_START);
@@ -77,7 +81,7 @@
Parrot_StringIterator_attributes * const clone_attrs =
PARROT_STRINGITERATOR(clone);
- clone_attrs->pos = attrs->pos;
+ clone_attrs->iter = attrs->iter;
clone_attrs->reverse = attrs->reverse;
return clone;
}
@@ -110,9 +114,9 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
if (attrs->reverse)
- return attrs->pos;
+ return attrs->iter.charpos;
else
- return attrs->length - attrs->pos;
+ return attrs->length - attrs->iter.charpos;
}
VTABLE INTVAL get_integer() {
@@ -137,13 +141,13 @@
PARROT_STRINGITERATOR(SELF);
if (value == ITERATE_FROM_START) {
attrs->reverse = 0;
- attrs->pos = 0;
attrs->length = VTABLE_elements(INTERP, attrs->string);
+ ENCODING_ITER_SET_POSITION(INTERP, &attrs->iter, 0);
}
else if (value == ITERATE_FROM_END) {
attrs->reverse = 1;
- attrs->pos = attrs->length
- = VTABLE_elements(INTERP, attrs->string);
+ attrs->length = VTABLE_elements(INTERP, attrs->string);
+ ENCODING_ITER_SET_POSITION(INTERP, &attrs->iter, attrs->length);
}
else
Parrot_ex_throw_from_c_args(INTERP, NULL,
EXCEPTION_INVALID_OPERATION,
@@ -179,14 +183,16 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
PMC *ret;
+ STRING *str;
- if (attrs->pos >= attrs->length)
+ if (attrs->iter.charpos >= attrs->length)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
ret = pmc_new(INTERP, Parrot_get_ctx_HLL_type(interp,
enum_class_String));
- VTABLE_set_string_native(INTERP, ret,
- VTABLE_get_string_keyed_int(INTERP, attrs->string,
attrs->pos++));
+ str = Parrot_str_iter_get_and_advance(interp,
+ VTABLE_get_string(INTERP, attrs->string), &attrs->iter);
+ VTABLE_set_string_native(INTERP, ret, str);
return ret;
}
@@ -203,11 +209,12 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
- if (attrs->pos >= attrs->length)
+ if (attrs->iter.charpos >= attrs->length)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
- return VTABLE_get_string_keyed_int(INTERP, attrs->string,
attrs->pos++);
+ return Parrot_str_iter_get_and_advance(interp,
+ VTABLE_get_string(INTERP, attrs->string), &attrs->iter);
}
/*
@@ -223,11 +230,11 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
- if (attrs->pos >= attrs->length)
+ if (attrs->iter.charpos >= attrs->length)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
- return VTABLE_get_integer_keyed_int(INTERP, attrs->string,
attrs->pos++);
+ return ENCODING_ITER_GET_AND_ADVANCE(INTERP, &attrs->iter);
}
/*
@@ -243,14 +250,16 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
PMC *ret;
+ STRING * str;
- if (!STATICSELF.get_bool())
+ if (attrs->iter.charpos <= 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
ret = pmc_new(INTERP, Parrot_get_ctx_HLL_type(interp,
enum_class_String));
- VTABLE_set_string_native(INTERP, ret,
- VTABLE_get_string_keyed_int(INTERP, attrs->string,
--attrs->pos));
+ str = Parrot_str_iter_regress_and_get(interp,
+ VTABLE_get_string(INTERP, attrs->string), &attrs->iter);
+ VTABLE_set_string_native(INTERP, ret, str);
return ret;
}
@@ -267,11 +276,12 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
- if (!STATICSELF.get_bool())
+ if (attrs->iter.charpos <= 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
- return VTABLE_get_string_keyed_int(INTERP, attrs->string,
--attrs->pos);
+ return Parrot_str_iter_regress_and_get(interp,
+ VTABLE_get_string(INTERP, attrs->string), &attrs->iter);
}
/*
@@ -287,11 +297,11 @@
Parrot_StringIterator_attributes * const attrs =
PARROT_STRINGITERATOR(SELF);
- if (!STATICSELF.get_bool())
+ if (attrs->iter.charpos <= 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
- return VTABLE_get_integer_keyed_int(INTERP, attrs->string,
--attrs->pos);
+ return ENCODING_ITER_REGRESS_AND_GET(INTERP, &attrs->iter);
}
/*
@@ -306,7 +316,7 @@
VTABLE INTVAL get_integer_keyed_int(INTVAL idx) {
return VTABLE_get_integer_keyed_int(INTERP, STATICSELF.get_pmc(),
- PARROT_STRINGITERATOR(SELF)->pos + idx);
+ PARROT_STRINGITERATOR(SELF)->iter.charpos + idx);
}
/*
@@ -321,7 +331,7 @@
VTABLE STRING *get_string_keyed_int(INTVAL idx) {
return VTABLE_get_string_keyed_int(INTERP, STATICSELF.get_pmc(),
- PARROT_STRINGITERATOR(SELF)->pos + idx);
+ PARROT_STRINGITERATOR(SELF)->iter.charpos + idx);
}
}
Index: src/string/encoding/utf16.c
===================================================================
--- src/string/encoding/utf16.c (revision 43399)
+++ src/string/encoding/utf16.c (working copy)
@@ -154,6 +154,13 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*i);
+PARROT_WARN_UNUSED_RESULT
+static UINTVAL utf16_regress_and_decode(PARROT_INTERP,
+ ARGMOD(String_iter *i))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*i);
+
static void utf16_encode_and_advance(PARROT_INTERP,
ARGMOD(String_iter *i),
UINTVAL c)
@@ -220,6 +227,9 @@
#define ASSERT_ARGS_utf16_decode_and_advance __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(i))
+#define ASSERT_ARGS_utf16_regress_and_decode __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(i))
#define ASSERT_ARGS_utf16_encode_and_advance __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(i))
@@ -734,6 +744,33 @@
/*
+=item C<static UINTVAL utf16_regress_and_decode(PARROT_INTERP, String_iter *i)>
+
+Moves the string iterator C<i> to the previous UTF-16 codepoint.
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+static UINTVAL
+utf16_regress_and_decode(PARROT_INTERP, ARGMOD(String_iter *i))
+{
+ ASSERT_ARGS(utf16_regress_and_decode)
+ UChar *s = (UChar*) i->str->strstart;
+ UINTVAL c, pos;
+ pos = i->bytepos / sizeof (UChar);
+ /* TODO either make sure that we don't go past end or use SAFE
+ * iter versions
+ */
+ U16_PREV_UNSAFE(s, pos, c);
+ i->charpos--;
+ i->bytepos = pos * sizeof (UChar);
+ return c;
+}
+
+/*
+
=item C<static void utf16_encode_and_advance(PARROT_INTERP, String_iter *i,
UINTVAL c)>
@@ -843,6 +880,10 @@
codepoints,
bytes,
iter_init,
+ utf16_decode_and_advance,
+ utf16_encode_and_advance,
+ utf16_regress_and_decode,
+ utf16_set_position,
find_cclass
};
STRUCT_COPY_FROM_STRUCT(return_encoding, base_encoding);
Index: src/string/encoding/fixed_8.c
===================================================================
--- src/string/encoding/fixed_8.c (revision 43399)
+++ src/string/encoding/fixed_8.c (working copy)
@@ -50,6 +50,11 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*iter);
+static UINTVAL fixed8_get_prev(PARROT_INTERP, ARGMOD(String_iter *iter))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*iter);
+
static void fixed8_set_next(PARROT_INTERP,
ARGMOD(String_iter *iter),
UINTVAL c)
@@ -181,6 +186,9 @@
#define ASSERT_ARGS_fixed8_get_next __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(iter))
+#define ASSERT_ARGS_fixed8_get_prev __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(iter))
#define ASSERT_ARGS_fixed8_set_next __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(iter))
@@ -600,6 +608,24 @@
/*
+=item C<static UINTVAL fixed8_get_prev(PARROT_INTERP, String_iter *iter)>
+
+Moves the string iterator C<i> to the previous codepoint.
+
+=cut
+
+*/
+
+static UINTVAL
+fixed8_get_prev(PARROT_INTERP, ARGMOD(String_iter *iter))
+{
+ ASSERT_ARGS(fixed8_get_prev)
+ iter->bytepos--;
+ return get_byte(interp, iter->str, --iter->charpos);
+}
+
+/*
+
=item C<static void fixed8_set_next(PARROT_INTERP, String_iter *iter, UINTVAL
c)>
@@ -695,6 +721,10 @@
codepoints,
bytes,
iter_init,
+ fixed8_get_next,
+ fixed8_set_next,
+ fixed8_get_prev,
+ fixed8_set_position,
find_cclass
};
Index: src/string/encoding/utf8.c
===================================================================
--- src/string/encoding/utf8.c (revision 43399)
+++ src/string/encoding/utf8.c (working copy)
@@ -158,6 +158,12 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*i);
+static UINTVAL utf8_regress_and_decode(PARROT_INTERP,
+ ARGMOD(String_iter *i))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*i);
+
PARROT_CANNOT_RETURN_NULL
static void * utf8_encode(PARROT_INTERP, ARGIN(void *ptr), UINTVAL c)
__attribute__nonnull__(1)
@@ -238,6 +244,9 @@
#define ASSERT_ARGS_utf8_decode_and_advance __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(i))
+#define ASSERT_ARGS_utf8_regress_and_decode __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(i))
#define ASSERT_ARGS_utf8_encode __attribute__unused__ int _ASSERT_ARGS_CHECK =
(\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(ptr))
@@ -505,6 +514,30 @@
/*
+=item C<static UINTVAL utf8_regress_and_decode(PARROT_INTERP, String_iter *i)>
+
+The UTF-8 implementation of the string iterator's C<regress_and_get>
+function.
+
+=cut
+
+*/
+
+static UINTVAL
+utf8_regress_and_decode(PARROT_INTERP, ARGMOD(String_iter *i))
+{
+ ASSERT_ARGS(utf8_regress_and_decode)
+ const utf8_t *u8ptr = (utf8_t *)((char *)i->str->strstart + i->bytepos);
+
+ u8ptr--;
+ while (UTF8_IS_CONTINUATION(*u8ptr))
+ u8ptr--;
+
+ return utf8_decode(interp, u8ptr);
+}
+
+/*
+
=item C<static void utf8_encode_and_advance(PARROT_INTERP, String_iter *i,
UINTVAL c)>
@@ -1055,6 +1088,10 @@
codepoints,
bytes,
iter_init,
+ utf8_decode_and_advance,
+ utf8_encode_and_advance,
+ utf8_regress_and_decode,
+ utf8_set_position,
find_cclass
};
STRUCT_COPY_FROM_STRUCT(return_encoding, base_encoding);
Index: src/string/encoding/ucs2.c
===================================================================
--- src/string/encoding/ucs2.c (revision 43399)
+++ src/string/encoding/ucs2.c (working copy)
@@ -157,6 +157,12 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*i);
+static UINTVAL ucs2_regress_and_decode(PARROT_INTERP,
+ ARGMOD(String_iter *i))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*i);
+
static void ucs2_encode_and_advance(PARROT_INTERP,
ARGMOD(String_iter *i),
UINTVAL c)
@@ -216,6 +222,9 @@
#define ASSERT_ARGS_ucs2_decode_and_advance __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(i))
+#define ASSERT_ARGS_ucs2_regress_and_decode __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(i))
#define ASSERT_ARGS_ucs2_encode_and_advance __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(i))
@@ -611,6 +620,41 @@
/*
+=item C<static UINTVAL ucs2_regress_and_decode(PARROT_INTERP, String_iter *i)>
+
+Moves the string iterator C<i> to the previous UCS-2 codepoint.
+
+=cut
+
+*/
+
+static UINTVAL
+ucs2_regress_and_decode(PARROT_INTERP, ARGMOD(String_iter *i))
+{
+ ASSERT_ARGS(ucs2_regress_and_decode)
+
+#if PARROT_HAS_ICU
+ UChar * const s = (UChar*) i->str->strstart;
+ size_t pos = i->bytepos / sizeof (UChar);
+
+ /* TODO either make sure that we don't go past end or use SAFE
+ * iter versions
+ */
+ const UChar c = s[--pos];
+ i->charpos--;
+ i->bytepos = pos * sizeof (UChar);
+ return c;
+#else
+ /* This function must never be called if compiled without ICU.
+ * See TT #557
+ */
+ PARROT_ASSERT(0);
+ return (UINTVAL)0; /* Stop the static analyzers from panicing */
+#endif
+}
+
+/*
+
=item C<static void ucs2_encode_and_advance(PARROT_INTERP, String_iter *i,
UINTVAL c)>
@@ -729,6 +773,10 @@
codepoints,
bytes,
iter_init,
+ ucs2_decode_and_advance,
+ ucs2_encode_and_advance,
+ ucs2_regress_and_decode,
+ ucs2_set_position,
find_cclass
};
STRUCT_COPY_FROM_STRUCT(return_encoding, base_encoding);
Index: src/string/api.c
===================================================================
--- src/string/api.c (revision 43399)
+++ src/string/api.c (working copy)
@@ -1254,9 +1254,74 @@
}
}
+/*
+=item C<STRING * Parrot_str_iter_get_and_advance(PARROT_INTERP, STRING *str,
+String_iter *iter)>
+
+Returns the character in C<str> that C<iter> points to and advances C<iter>.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+STRING *
+Parrot_str_iter_get_and_advance(PARROT_INTERP,
+ ARGIN(STRING *str), ARGOUT(String_iter *iter))
+{
+ ASSERT_ARGS(Parrot_str_iter_get_and_advance)
+ STRING *dest = Parrot_str_new_COW(interp, str);
+ UINTVAL start = iter->bytepos;
+
+ ENCODING_ITER_GET_AND_ADVANCE(interp, iter);
+
+ dest->strstart = (char *)dest->strstart + start;
+ dest->bufused = iter->bytepos - start;
+ dest->strlen = 1;
+ dest->hashval = 0;
+
+ return dest;
+}
+
/*
+=item C<STRING * Parrot_str_iter_regress_and_get(PARROT_INTERP, STRING *str,
+String_iter *iter)>
+
+Moves C<iter> backwards and returns the character in C<str> that C<iter>
+points to.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+STRING *
+Parrot_str_iter_regress_and_get(PARROT_INTERP,
+ ARGIN(STRING *str), ARGOUT(String_iter *iter))
+{
+ ASSERT_ARGS(Parrot_str_iter_get_and_advance)
+ STRING *dest = Parrot_str_new_COW(interp, str);
+ UINTVAL end = iter->bytepos;
+
+ ENCODING_ITER_REGRESS_AND_GET(interp, iter);
+
+ dest->strstart = (char *)dest->strstart + iter->bytepos;
+ dest->bufused = end - iter->bytepos;
+ dest->strlen = 1;
+ dest->hashval = 0;
+
+ return dest;
+}
+
+
+/*
+
=item C<STRING * Parrot_str_replace(PARROT_INTERP, STRING *src, INTVAL offset,
INTVAL length, STRING *rep, STRING **d)>
Index: include/parrot/encoding.h
===================================================================
--- include/parrot/encoding.h (revision 43399)
+++ include/parrot/encoding.h (working copy)
@@ -37,6 +37,10 @@
typedef void (*encoding_iter_init_t)(PARROT_INTERP, const STRING *src,
struct string_iterator_t *);
+typedef UINTVAL (*encoding_iter_get_and_advance_t)(PARROT_INTERP, struct
string_iterator_t *);
+typedef void (*encoding_iter_set_and_advance_t)(PARROT_INTERP, struct
string_iterator_t *, UINTVAL);
+typedef UINTVAL (*encoding_iter_regress_and_get_t)(PARROT_INTERP, struct
string_iterator_t *);
+typedef void (*encoding_iter_set_position_t)(PARROT_INTERP, struct
string_iterator_t *, UINTVAL);
struct _encoding {
ARGIN(const char *name);
@@ -56,6 +60,10 @@
encoding_codepoints_t codepoints;
encoding_bytes_t bytes;
encoding_iter_init_t iter_init;
+ encoding_iter_get_and_advance_t iter_get_and_advance;
+ encoding_iter_set_and_advance_t iter_set_and_advance;
+ encoding_iter_regress_and_get_t iter_regress_and_get;
+ encoding_iter_set_position_t iter_set_position;
encoding_find_cclass_t find_cclass;
};
@@ -220,6 +228,14 @@
((src)->encoding)->bytes((i), (src))
#define ENCODING_ITER_INIT(i, src, iter) \
((src)->encoding)->iter_init((i), (src), (iter))
+#define ENCODING_ITER_GET_AND_ADVANCE(i, iter) \
+ ((iter)->str->encoding)->iter_get_and_advance((i), (iter))
+#define ENCODING_ITER_SET_AND_ADVANCE(i, iter, c) \
+ ((iter)->str->encoding)->iter_set_and_advance((i), (iter), (c))
+#define ENCODING_ITER_REGRESS_AND_GET(i, iter) \
+ ((iter)->str->encoding)->iter_regress_and_get((i), (iter))
+#define ENCODING_ITER_SET_POSITION(i, iter, pos) \
+ ((iter)->str->encoding)->iter_set_position((i), (iter), (pos))
#define ENCODING_FIND_CCLASS(i, src, typetable, flags, pos, end) \
((src)->encoding)->find_cclass((i), (src), (typetable), (flags), (pos),
(end))
Index: include/parrot/string_funcs.h
===================================================================
--- include/parrot/string_funcs.h (revision 43399)
+++ include/parrot/string_funcs.h (working copy)
@@ -391,6 +391,24 @@
PARROT_EXPORT
PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+STRING * Parrot_str_iter_get_and_advance(PARROT_INTERP,
+ ARGIN(STRING *str),
+ ARGOUT(String_iter *iter))
+ __attribute__nonnull__(1)
+ FUNC_MODIFIES(*iter);
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+STRING * Parrot_str_iter_regress_and_get(PARROT_INTERP,
+ ARGIN(STRING *str),
+ ARGOUT(String_iter *iter))
+ __attribute__nonnull__(1)
+ FUNC_MODIFIES(*iter);
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
PARROT_MALLOC
STRING * Parrot_str_titlecase(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
__attribute__nonnull__(1);
@@ -660,6 +678,10 @@
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_str_substr __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_str_iter_get_and_advance __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_str_iter_regress_and_get __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_str_titlecase __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_str_titlecase_inplace __attribute__unused__ int
_ASSERT_ARGS_CHECK = (\
_______________________________________________
http://lists.parrot.org/mailman/listinfo/parrot-dev