Use of iterators

2014/08/21 09:57
Reading number 173

The common mode of container library in stl is to separate containers, iterators and algorithms. Containers are dedicated to storage, and iterators are responsible for enumeration. This independence has many benefits.

Therefore, TBOX also draws on this model. The difference is that there is no template, but only c language. Most containers in the container library are inherited from iterators, so it is very convenient to iterate.

Let's take a look at an example of the use of iterators:

 //Initialize a two-way linked list, the element type is tb_long_t, and the full 256 elements will grow automatically tb_list_ref_t list = tb_list_init(256, tb_item_func_long()); if (list) { //Insert some elements tb_list_insert_tail(list, (tb_cpointer_t)1); tb_list_insert_tail(list, (tb_cpointer_t)2); tb_list_insert_tail(list, (tb_cpointer_t)3); tb_list_insert_tail(list, (tb_cpointer_t)4); tb_list_insert_tail(list, (tb_cpointer_t)5); //Iterate through all elements tb_for_all (tb_long_t, item, list) { tb_trace_i("item: %ld", item); } //Iterative traversal of all elements>3 tb_for_all_if (tb_long_t,  item, list, item > 3) { tb_trace_i("item: %ld", item); } //Reverse iteration traverses all elements. Note: only containers that support reverse iteration can do this. For example, single chain tb_single_list_t cannot tb_rfor_all (tb_long_t, item, list) { tb_trace_i("item: %ld", item); } //Reverse iteration traverses all elements>3 tb_rfor_all_if (tb_long_t,  item, list, item > 3) { tb_trace_i("item: %ld", item); } //Iterative traversal of some elements. It is considered that the head and tail of the iteration are passed in, and all elements are traversed tb_for (tb_long_t, item, tb_iterator_head(list), tb_iterator_tail(list), list) { tb_trace_i("item: %ld", item); } //Exit linked list tb_list_exit(list); }

How simple is it? In fact, tb_for_all here is a macro. If you expand it, you can actually traverse it in this way, but it seems more complicated, but it is more flexible:

 //Get the header index of the list tb_size_t itor = tb_iterator_head(list); //Get the tail index of the list tb_size_t tail = tb_iterator_tail(list); //Traversal. The element is not deleted here, so the value of tail does not need to be updated in real time for (;  itor != tail; itor = tb_iterator_next(list, itor)) { //Get the element corresponding to the index monitor tb_long_t item = (tb_long_t)tb_iterator_item(list, itor); } //To traverse and delete elements, the tail needs to be updated, so the tb_for cannot be used //Tb_for will not update the value of tail for efficiency while (itor !=  tb_iterator_tail(list, itor)) { //Get the element corresponding to the index monitor tb_long_t item = (tb_long_t)tb_iterator_item(list, itor); if (item > 3) { //Save the next index first to avoid deleting the current element and making the tor invalid tb_size_t next = tb_iterator_next(list, itor); //Use iterator to delete tb_iterator_remove(list, itor); //Or use container to delete //      tb_list_remove(list, itor); //Continue to the next itor = next; continue ; } //Continue to the next itor = tb_iterator_next(list, itor); }

In fact, this method is quite convenient. If you think the above deletion is complicated, you can use the remove function provided by the algorithm library to traverse the deletion, and it is more efficient.

 //Callback function tb_long_t tb_list_item_func(tb_iterator_ref_t iterator,  tb_cpointer_t item, tb_cpointer_t priv); { //If>3, delete it if ((tb_long_t)item > 3) { /*Mark this element for deletion *  *Note: *At this time, the container has not been deleted, and some optimizations have been made *To delete one continuous element at a time, which will be much more efficient * *This deletion mode is the fastest, especially for tb_vector_t, a container with continuous memory, which is more efficient *It avoids moving tb_memov memory once every element is deleted * *The name is similar. Vector traversal and deletion use: tb_vector_walk */ return 0; } //Return 1 to continue the next one, and return - 1 to interrupt traversal return 1; } //Traverse all elements and call the callback function for each element tb_remove_if(list,  tb_list_item_func, tb_null);

Another traversal method is to use the tb_walk function of the algorithm library, which is similar to tb_list_walk, but does not provide the deletion function. It is mainly used in general, modular and complex traversal code:

 tb_bool_t tb_walk_item_func(tb_iterator_ref_t iterator,  tb_pointer_t item, tb_pointer_t priv) { // ... } //Traverse all tb_walk_all(list,  tb_walk_item_func, tb_null); //Reverse traverse all tb_rwalk_all(list,  tb_walk_item_func, tb_null); //Local traversal through iterator index tb_walk(list, tb_iterator_head(list), tb_iterator_tail(list),  tb_walk_item_func, tb_null); //Reverse through iterator index, local traversal tb_rwalk(list, tb_iterator_head(list), tb_iterator_tail(list),  tb_walk_item_func, tb_null);

To sum up:

  1. Tb_for series: simple logical traversal for small code blocks
  2. Direct use of iterators: for complex logic traversal of small code blocks
  3. Container tb_xxx_walk: used for traversing complex code blocks and efficiently deleting elements
  4. Tb_walk series: for complex code blocks, traversal when deletion is not required

Iterator mainly consists of the following access modes, and different containers support different levels:

 /// the iterator mode type typedef enum __tb_iterator_mode_t { TB_ITERATOR_MODE_FORWARD=1//!<Forward traversal iterator, which is supported by most containers , TB_ITERATOR_MODE_REVERSE=2//!<Reverse traversal iterator, single chain does not support , TB_ITERATOR_MODE_RACCESS=4//!<Random access iterators, linked lists, queues, stacks, etc. are not supported. Vector is the most commonly used , TB_ITERATOR_MODE_MUTABLE=8//!<A mutable iterator. The index value of the same iterator may change due to deleting an element, such as vector , TB_ITERATOR_MODE_READONLY=16//!<Read only access iterator, deletion, replacement and other operations are not available }tb_iterator_mode_t;

Common iterator interfaces:

 //Get iterator access mode tb_size_t       tb_iterator_mode(tb_iterator_ref_t iterator); //Get the total number of elements of the container corresponding to the iterator tb_size_t       tb_iterator_size(tb_iterator_ref_t iterator); //Get the header index of the iterator tb_size_t       tb_iterator_head(tb_iterator_ref_t iterator); //Get the index of the last element of the iterator tb_size_t       tb_iterator_last(tb_iterator_ref_t iterator); //Get the tail index of the iterator, which does not point to the actual element, and is generally used to determine the end tb_size_t       tb_iterator_tail(tb_iterator_ref_t iterator); //Get the index of the previous element of the iterator tb_size_t       tb_iterator_prev(tb_iterator_ref_t iterator, tb_size_t itor); //Get the index of the next element of the iterator tb_size_t       tb_iterator_next(tb_iterator_ref_t iterator, tb_size_t itor); //Get the element pointed to by the iterator index tb_pointer_t    tb_iterator_item(tb_iterator_ref_t iterator, tb_size_t itor); //Delete the element pointed to by the iterator index tb_void_t       tb_iterator_remove(tb_iterator_ref_t iterator, tb_size_t itor); //Copy the element pointed to by the iterator index tb_void_t       tb_iterator_copy(tb_iterator_ref_t iterator,  tb_size_t itor, tb_cpointer_t item); //Compare the two elements pointed to by the iterator index tb_long_t       tb_iterator_comp(tb_iterator_ref_t iterator,  tb_cpointer_t ltem, tb_cpointer_t rtem);

You can also iterate the commonly used original array to support iteration and apply it to all algorithms:

 //Generate iterator according to a tb_long_t [] array, and size is the number of array elements tb_iterator_t   tb_iterator_init_long(tb_long_t* data, tb_size_t size); //Generate iterator according to a tb_size_t [] array, size is the number of array elements tb_iterator_t   tb_iterator_init_size(tb_size_t* data, tb_size_t size); //Generate iterator according to a tb_char_t * [] string array, and size is the number of array elements tb_iterator_t   tb_iterator_init_str(tb_char_t** data, tb_size_t size); //Generate iterator according to a tb_pointer_t [] pointer array, and size is the number of array elements tb_iterator_t   tb_iterator_init_ptr(tb_pointer_t* data, tb_size_t size); //Generate iterator according to a tb_struct_xxxx_t [] structure array, size is the number of array elements, step==sizeof (tb_struct_xxxx_t) tb_iterator_t   tb_iterator_init_mem(tb_pointer_t data,  tb_size_t size, tb_size_t step);

Expand to read the full text
Loading
Click to lead the topic 📣 Post and join the discussion 🔥
Reward
zero comment
zero Collection
zero fabulous
 Back to top
Top