@@ -107,7 +107,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
107107 // TODO: need predicate to check for int-like type (bools are such for example)
108108 // ["no", "yes"][1 == 2] is common idiom
109109 if (MP_OBJ_IS_SMALL_INT (rhs_in )) {
110- uint index = mp_get_index (mp_obj_get_type (lhs_in ), lhs_len , rhs_in );
110+ uint index = mp_get_index (mp_obj_get_type (lhs_in ), lhs_len , rhs_in , false );
111111 if (MP_OBJ_IS_TYPE (lhs_in , & bytes_type )) {
112112 return MP_OBJ_NEW_SMALL_INT ((mp_small_int_t )lhs_data [index ]);
113113 } else {
@@ -290,10 +290,10 @@ STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) {
290290 size_t end = haystack_len ;
291291 /* TODO use a non-exception-throwing mp_get_index */
292292 if (n_args >= 3 && args [2 ] != mp_const_none ) {
293- start = mp_get_index (& str_type , haystack_len , args [2 ]);
293+ start = mp_get_index (& str_type , haystack_len , args [2 ], true );
294294 }
295295 if (n_args >= 4 && args [3 ] != mp_const_none ) {
296- end = mp_get_index (& str_type , haystack_len , args [3 ]);
296+ end = mp_get_index (& str_type , haystack_len , args [3 ], true );
297297 }
298298
299299 const byte * p = find_subbytes (haystack + start , haystack_len - start , needle , needle_len );
@@ -487,6 +487,41 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
487487 return mp_obj_str_builder_end (replaced_str );
488488}
489489
490+ STATIC mp_obj_t str_count (uint n_args , const mp_obj_t * args ) {
491+ assert (2 <= n_args && n_args <= 4 );
492+ assert (MP_OBJ_IS_STR (args [0 ]));
493+ assert (MP_OBJ_IS_STR (args [1 ]));
494+
495+ GET_STR_DATA_LEN (args [0 ], haystack , haystack_len );
496+ GET_STR_DATA_LEN (args [1 ], needle , needle_len );
497+
498+ size_t start = 0 ;
499+ size_t end = haystack_len ;
500+ /* TODO use a non-exception-throwing mp_get_index */
501+ if (n_args >= 3 && args [2 ] != mp_const_none ) {
502+ start = mp_get_index (& str_type , haystack_len , args [2 ], true);
503+ }
504+ if (n_args >= 4 && args [3 ] != mp_const_none ) {
505+ end = mp_get_index (& str_type , haystack_len , args [3 ], true);
506+ }
507+
508+ machine_int_t num_occurrences = 0 ;
509+
510+ // needle won't exist in haystack if it's longer, so nothing to count
511+ if (needle_len > haystack_len ) {
512+ MP_OBJ_NEW_SMALL_INT (0 );
513+ }
514+
515+ for (machine_uint_t haystack_index = start ; haystack_index + needle_len <= end ; haystack_index ++ ) {
516+ if (memcmp (& haystack [haystack_index ], needle , needle_len ) == 0 ) {
517+ num_occurrences ++ ;
518+ haystack_index += needle_len - 1 ;
519+ }
520+ }
521+
522+ return MP_OBJ_NEW_SMALL_INT (num_occurrences );
523+ }
524+
490525STATIC machine_int_t str_get_buffer (mp_obj_t self_in , buffer_info_t * bufinfo , int flags ) {
491526 if (flags == BUFFER_READ ) {
492527 GET_STR_DATA_LEN (self_in , str_data , str_len );
@@ -508,6 +543,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith);
508543STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_strip_obj , 1 , 2 , str_strip );
509544STATIC MP_DEFINE_CONST_FUN_OBJ_VAR (str_format_obj , 1 , str_format );
510545STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_replace_obj , 3 , 4 , str_replace );
546+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_count_obj , 2 , 4 , str_count );
511547
512548STATIC const mp_method_t str_type_methods [] = {
513549 { "find" , & str_find_obj },
@@ -517,6 +553,7 @@ STATIC const mp_method_t str_type_methods[] = {
517553 { "strip" , & str_strip_obj },
518554 { "format" , & str_format_obj },
519555 { "replace" , & str_replace_obj },
556+ { "count" , & str_count_obj },
520557 { NULL , NULL }, // end-of-list sentinel
521558};
522559
0 commit comments