@@ -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,46 @@ 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 <= end ; haystack_index ++ ) {
516+ for (machine_uint_t needle_index = 0 ; needle_index < needle_len ; needle_index ++ ) {
517+ if ((haystack_index + needle_len ) > end ) {
518+ return MP_OBJ_NEW_SMALL_INT (num_occurrences );
519+ }
520+ if (haystack [haystack_index + needle_index ] == needle [needle_index ] && needle_index == (needle_len - 1 )) {
521+ num_occurrences ++ ;
522+ }
523+
524+ }
525+ }
526+
527+ return MP_OBJ_NEW_SMALL_INT (num_occurrences );
528+ }
529+
490530STATIC machine_int_t str_get_buffer (mp_obj_t self_in , buffer_info_t * bufinfo , int flags ) {
491531 if (flags == BUFFER_READ ) {
492532 GET_STR_DATA_LEN (self_in , str_data , str_len );
@@ -508,6 +548,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith);
508548STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_strip_obj , 1 , 2 , str_strip );
509549STATIC MP_DEFINE_CONST_FUN_OBJ_VAR (str_format_obj , 1 , str_format );
510550STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_replace_obj , 3 , 4 , str_replace );
551+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_count_obj , 2 , 4 , str_count );
511552
512553STATIC const mp_method_t str_type_methods [] = {
513554 { "find" , & str_find_obj },
@@ -517,6 +558,7 @@ STATIC const mp_method_t str_type_methods[] = {
517558 { "strip" , & str_strip_obj },
518559 { "format" , & str_format_obj },
519560 { "replace" , & str_replace_obj },
561+ { "count" , & str_count_obj },
520562 { NULL , NULL }, // end-of-list sentinel
521563};
522564
0 commit comments