@@ -14,9 +14,11 @@ typedef struct _mp_obj_str_t {
1414 mp_obj_base_t base ;
1515 machine_uint_t hash : 16 ; // XXX here we assume the hash size is 16 bits (it is at the moment; see qstr.c)
1616 machine_uint_t len : 16 ; // len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte
17- byte data [] ;
17+ const byte * data ;
1818} mp_obj_str_t ;
1919
20+ const mp_obj_t mp_const_empty_bytes ;
21+
2022// use this macro to extract the string hash
2123#define GET_STR_HASH (str_obj_in , str_hash ) uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
2224
@@ -28,6 +30,7 @@ typedef struct _mp_obj_str_t {
2830
2931STATIC mp_obj_t mp_obj_new_str_iterator (mp_obj_t str );
3032STATIC mp_obj_t mp_obj_new_bytes_iterator (mp_obj_t str );
33+ STATIC mp_obj_t str_new (const mp_obj_type_t * type , const byte * data , uint len );
3134
3235/******************************************************************************/
3336/* str */
@@ -78,6 +81,109 @@ STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env,
7881 }
7982}
8083
84+ STATIC mp_obj_t str_make_new (mp_obj_t type_in , uint n_args , uint n_kw , const mp_obj_t * args ) {
85+ switch (n_args ) {
86+ case 0 :
87+ return MP_OBJ_NEW_QSTR (MP_QSTR_ );
88+
89+ case 1 :
90+ {
91+ vstr_t * vstr = vstr_new ();
92+ mp_obj_print_helper ((void (* )(void * , const char * , ...))vstr_printf , vstr , args [0 ], PRINT_STR );
93+ mp_obj_t s = mp_obj_new_str ((byte * )vstr -> buf , vstr -> len , false);
94+ vstr_free (vstr );
95+ return s ;
96+ }
97+
98+ case 2 :
99+ case 3 :
100+ {
101+ // TODO: validate 2nd/3rd args
102+ if (!MP_OBJ_IS_TYPE (args [0 ], & bytes_type )) {
103+ nlr_jump (mp_obj_new_exception_msg (& mp_type_TypeError , "bytes expected" ));
104+ }
105+ GET_STR_DATA_LEN (args [0 ], str_data , str_len );
106+ GET_STR_HASH (args [0 ], str_hash );
107+ mp_obj_str_t * o = str_new (& str_type , NULL , str_len );
108+ o -> data = str_data ;
109+ o -> hash = str_hash ;
110+ return o ;
111+ }
112+
113+ default :
114+ nlr_jump (mp_obj_new_exception_msg (& mp_type_TypeError , "str takes at most 3 arguments" ));
115+ }
116+ }
117+
118+ STATIC mp_obj_t bytes_make_new (mp_obj_t type_in , uint n_args , uint n_kw , const mp_obj_t * args ) {
119+ if (n_args == 0 ) {
120+ return mp_const_empty_bytes ;
121+ }
122+
123+ if (MP_OBJ_IS_STR (args [0 ])) {
124+ if (n_args < 2 || n_args > 3 ) {
125+ goto wrong_args ;
126+ }
127+ GET_STR_DATA_LEN (args [0 ], str_data , str_len );
128+ GET_STR_HASH (args [0 ], str_hash );
129+ mp_obj_str_t * o = str_new (& bytes_type , NULL , str_len );
130+ o -> data = str_data ;
131+ o -> hash = str_hash ;
132+ return o ;
133+ }
134+
135+ if (n_args > 1 ) {
136+ goto wrong_args ;
137+ }
138+
139+ if (MP_OBJ_IS_SMALL_INT (args [0 ])) {
140+ uint len = MP_OBJ_SMALL_INT_VALUE (args [0 ]);
141+ byte * data ;
142+
143+ mp_obj_t o = mp_obj_str_builder_start (& bytes_type , len , & data );
144+ memset (data , 0 , len );
145+ return mp_obj_str_builder_end (o );
146+ }
147+
148+ int len ;
149+ byte * data ;
150+ vstr_t * vstr = NULL ;
151+ mp_obj_t o = NULL ;
152+ // Try to create array of exact len if initializer len is known
153+ mp_obj_t len_in = mp_obj_len_maybe (args [0 ]);
154+ if (len_in == MP_OBJ_NULL ) {
155+ len = -1 ;
156+ vstr = vstr_new ();
157+ } else {
158+ len = MP_OBJ_SMALL_INT_VALUE (len_in );
159+ o = mp_obj_str_builder_start (& bytes_type , len , & data );
160+ }
161+
162+ mp_obj_t iterable = rt_getiter (args [0 ]);
163+ mp_obj_t item ;
164+ while ((item = rt_iternext (iterable )) != mp_const_stop_iteration ) {
165+ if (len == -1 ) {
166+ vstr_add_char (vstr , MP_OBJ_SMALL_INT_VALUE (item ));
167+ } else {
168+ * data ++ = MP_OBJ_SMALL_INT_VALUE (item );
169+ }
170+ }
171+
172+ if (len == -1 ) {
173+ vstr_shrink (vstr );
174+ // TODO: Optimize, borrow buffer from vstr
175+ len = vstr_len (vstr );
176+ o = mp_obj_str_builder_start (& bytes_type , len , & data );
177+ memcpy (data , vstr_str (vstr ), len );
178+ vstr_free (vstr );
179+ }
180+
181+ return mp_obj_str_builder_end (o );
182+
183+ wrong_args :
184+ nlr_jump (mp_obj_new_exception_msg (& mp_type_TypeError , "wrong number of arguments" ));
185+ }
186+
81187// like strstr but with specified length and allows \0 bytes
82188// TODO replace with something more efficient/standard
83189STATIC const byte * find_subbytes (const byte * haystack , uint hlen , const byte * needle , uint nlen ) {
@@ -520,6 +626,62 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) {
520626 return MP_OBJ_NEW_SMALL_INT (num_occurrences );
521627}
522628
629+ STATIC mp_obj_t str_partitioner (mp_obj_t self_in , mp_obj_t arg , machine_int_t direction ) {
630+ assert (MP_OBJ_IS_STR (self_in ));
631+ if (!MP_OBJ_IS_STR (arg )) {
632+ nlr_jump (mp_obj_new_exception_msg_varg (& mp_type_TypeError ,
633+ "Can't convert '%s' object to str implicitly" , mp_obj_get_type_str (arg )));
634+ }
635+
636+ GET_STR_DATA_LEN (self_in , str , str_len );
637+ GET_STR_DATA_LEN (arg , sep , sep_len );
638+
639+ if (sep_len == 0 ) {
640+ nlr_jump (mp_obj_new_exception_msg (& mp_type_ValueError , "empty separator" ));
641+ }
642+
643+ mp_obj_t result [] = {MP_OBJ_NEW_QSTR (MP_QSTR_ ), MP_OBJ_NEW_QSTR (MP_QSTR_ ), MP_OBJ_NEW_QSTR (MP_QSTR_ )};
644+
645+ if (direction > 0 ) {
646+ result [0 ] = self_in ;
647+ } else {
648+ result [2 ] = self_in ;
649+ }
650+
651+ if (str_len >= sep_len ) {
652+ machine_uint_t str_index , str_index_end ;
653+ if (direction > 0 ) {
654+ str_index = 0 ;
655+ str_index_end = str_len - sep_len ;
656+ } else {
657+ str_index = str_len - sep_len ;
658+ str_index_end = 0 ;
659+ }
660+ for (;;) {
661+ if (memcmp (& str [str_index ], sep , sep_len ) == 0 ) {
662+ result [0 ] = mp_obj_new_str (str , str_index , false);
663+ result [1 ] = arg ;
664+ result [2 ] = mp_obj_new_str (str + str_index + sep_len , str_len - str_index - sep_len , false);
665+ break ;
666+ }
667+ if (str_index == str_index_end ) {
668+ break ;
669+ }
670+ str_index += direction ;
671+ }
672+ }
673+
674+ return mp_obj_new_tuple (3 , result );
675+ }
676+
677+ STATIC mp_obj_t str_partition (mp_obj_t self_in , mp_obj_t arg ) {
678+ return str_partitioner (self_in , arg , 1 );
679+ }
680+
681+ STATIC mp_obj_t str_rpartition (mp_obj_t self_in , mp_obj_t arg ) {
682+ return str_partitioner (self_in , arg , -1 );
683+ }
684+
523685STATIC machine_int_t str_get_buffer (mp_obj_t self_in , buffer_info_t * bufinfo , int flags ) {
524686 if (flags == BUFFER_READ ) {
525687 GET_STR_DATA_LEN (self_in , str_data , str_len );
@@ -542,6 +704,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
542704STATIC MP_DEFINE_CONST_FUN_OBJ_VAR (str_format_obj , 1 , str_format );
543705STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_replace_obj , 3 , 4 , str_replace );
544706STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_count_obj , 2 , 4 , str_count );
707+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (str_partition_obj , str_partition );
708+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (str_rpartition_obj , str_rpartition );
545709
546710STATIC const mp_method_t str_type_methods [] = {
547711 { "find" , & str_find_obj },
@@ -552,13 +716,16 @@ STATIC const mp_method_t str_type_methods[] = {
552716 { "format" , & str_format_obj },
553717 { "replace" , & str_replace_obj },
554718 { "count" , & str_count_obj },
719+ { "partition" , & str_partition_obj },
720+ { "rpartition" , & str_rpartition_obj },
555721 { NULL , NULL }, // end-of-list sentinel
556722};
557723
558724const mp_obj_type_t str_type = {
559725 { & mp_type_type },
560726 .name = MP_QSTR_str ,
561727 .print = str_print ,
728+ .make_new = str_make_new ,
562729 .binary_op = str_binary_op ,
563730 .getiter = mp_obj_new_str_iterator ,
564731 .methods = str_type_methods ,
@@ -570,34 +737,45 @@ const mp_obj_type_t bytes_type = {
570737 { & mp_type_type },
571738 .name = MP_QSTR_bytes ,
572739 .print = str_print ,
740+ .make_new = bytes_make_new ,
573741 .binary_op = str_binary_op ,
574742 .getiter = mp_obj_new_bytes_iterator ,
575743 .methods = str_type_methods ,
576744};
577745
746+ // the zero-length bytes
747+ STATIC const mp_obj_str_t empty_bytes_obj = {{& bytes_type }, 0 , 0 , NULL };
748+ const mp_obj_t mp_const_empty_bytes = (mp_obj_t )& empty_bytes_obj ;
749+
578750mp_obj_t mp_obj_str_builder_start (const mp_obj_type_t * type , uint len , byte * * data ) {
579- mp_obj_str_t * o = m_new_obj_var (mp_obj_str_t , byte , len + 1 );
751+ mp_obj_str_t * o = m_new_obj (mp_obj_str_t );
580752 o -> base .type = type ;
581753 o -> len = len ;
582- * data = o -> data ;
754+ byte * p = m_new (byte , len + 1 );
755+ o -> data = p ;
756+ * data = p ;
583757 return o ;
584758}
585759
586760mp_obj_t mp_obj_str_builder_end (mp_obj_t o_in ) {
587- assert (MP_OBJ_IS_STR (o_in ));
588761 mp_obj_str_t * o = o_in ;
589762 o -> hash = qstr_compute_hash (o -> data , o -> len );
590- o -> data [o -> len ] = '\0' ; // for now we add null for compatibility with C ASCIIZ strings
763+ byte * p = (byte * )o -> data ;
764+ p [o -> len ] = '\0' ; // for now we add null for compatibility with C ASCIIZ strings
591765 return o ;
592766}
593767
594768STATIC mp_obj_t str_new (const mp_obj_type_t * type , const byte * data , uint len ) {
595- mp_obj_str_t * o = m_new_obj_var (mp_obj_str_t , byte , len + 1 );
769+ mp_obj_str_t * o = m_new_obj (mp_obj_str_t );
596770 o -> base .type = type ;
597- o -> hash = qstr_compute_hash (data , len );
598771 o -> len = len ;
599- memcpy (o -> data , data , len * sizeof (byte ));
600- o -> data [len ] = '\0' ; // for now we add null for compatibility with C ASCIIZ strings
772+ if (data ) {
773+ o -> hash = qstr_compute_hash (data , len );
774+ byte * p = m_new (byte , len + 1 );
775+ o -> data = p ;
776+ memcpy (p , data , len * sizeof (byte ));
777+ p [len ] = '\0' ; // for now we add null for compatibility with C ASCIIZ strings
778+ }
601779 return o ;
602780}
603781
0 commit comments