// arg 传入callback中的参数。原则:该变量只能是静态常数, // 或者用malloc分配的独立变量,在callback中free或者close // 这是因为当多个callback被append时,非常难控制这个顺序。 // 例如: // const int some_id = some_id_open(); // batch_append( id, batch_callback_close_some_id, (void*)some_id ); // batch_append( id, batch_callback_display_some_id, (void*)some_id ); // 上面的顺序,就会导致第二个callback调用时,使用了已经被close的some_id。 // 另外一个解决方法是:增加一个batch_insert()方法,将batch_callback_display_some_id // 放在batch_callback_close_some_id前面,但这个方法,增加了 // batch模块设计难度,也增加了调用时的难度。如果arg之间依赖关系比较复杂, // batch_insert()就会有很多隐含的、难易发现、调试的问题。 bool batch_append( int id, batch_callback_t callback, void* arg ){ uverify( id_valid( id ) ); uverify( callback_arg_valid( callback, arg ) ); batch_t* const batch = (batch_t*)id; // 列表,满了? if( batch_full( id ) ){ if( !batch_auto_grow_up( id ) ){ uverify( false ); return false; } } uverify( !batch_full( id ) ); callback_arg_t* const free_ix = &(batch->list[batch->num]); uverify( callback_arg_is_default( free_ix ) ); if( !callback_arg_set( free_ix, callback, arg ) ){ uverify( false ); return false; } batch->num++; uverify( id_valid( id ) ); return true; }
// prev -> node -> next // => // prev -> next // return: ok? bool qdlink_delete( int id, int node_id ){ uverify( id_valid( id ) ); uverify( node_id_valid( node_id ) ); int prev_id = 0; if( node_id == qdlink_first( id ) ){ prev_id = id; } else{ prev_id = qdlink_prev( id, node_id ); // not found the node uverify( 0 != prev_id ); } return_false_if( 0 == prev_id ); node_t* const prev = (node_t*)prev_id; node_t* const node = (node_t*)node_id; node_t* const next = node->next; prev->next = next; next->prev = prev; if( GCFG_DEBUG_EN ){ node->next = NULL; node->prev = NULL; } free( node ); return true; }
int id_read_format(struct id *id, const char *buffer) { int out = 0; /* just strip out any dashes */ while (*buffer) { if (*buffer == '-') { buffer++; continue; } if (out >= ID_LEN) { log_error("Too many characters to be uuid."); return 0; } id->uuid[out++] = *buffer++; } if (out != ID_LEN) { log_error("Couldn't read uuid: incorrect number of " "characters."); return 0; } return id_valid(id); }
int qdlink_at( int id, int ix ){ uverify( id_valid( id ) ); uverify( ix_valid( ix ) ); ix_callback_t arg = { ix, 0 }; qdlink_for_each( id, qdlink_ix_callback, &arg ); return arg.result_id; }
static bool batch_close( int id ){ uverify( id_valid( id ) ); batch_t* p = (batch_t*)id; qfreez( p->list ); qfreez( p ); return true; }
bool qdlink_close( int id ){ uverify( id_valid( id ) ); qdlink_delete_all( id ); node_t* const node = (node_t*)id; free( node ); return true; }
static bool batch_full( int id ){ uverify( id_valid( id ) ); batch_t* const batch = (batch_t*)id; if( batch->num < batch->len ){ return false; } return true; }
bool qdlink_empty( int id ){ uverify( id_valid( id ) ); const node_t* const node = (node_t*)id; if( node == node->next ){ uverify( node == node->prev ); return true; } return false; }
// return; node_id int qdlink_last( int id ){ uverify( id_valid( id ) ); if( qdlink_empty( id ) ){ return 0; } node_t* const node = (node_t*)id; node_t* const p = node->prev; return (int)p; }
// if node_id is the first node, will return 0 // return: node_id int qdlink_prev( int id, int node_id ){ uverify( id_valid( id ) ); uverify( node_id_valid( node_id ) ); node_t* const node = (node_t*)node_id; node_t* const p = node->prev; // first node? if( (int)p == id ){ return 0; } return (int)p; }
static bool batch_auto_grow_up( int id ){ uverify( id_valid( id ) ); batch_t* const batch = (batch_t*)id; const int len = batch->len; const int increase_len = 50; const int new_len = len + increase_len; callback_arg_t* const new_list = qrealloc( batch->list, new_len * sizeof( callback_arg_t ) ); // 如果没有足够的空间,老空间没有释放,仍然存在。简单返回false,说明grow_up失败。 return_false_if( NULL == new_list ); batch->list = new_list; // 老空间内容,已经拷贝在前面,只用初始化后面一段即可。 return_false_if( !init_list( batch->list + len, increase_len ) ); batch->len = new_len; uverify( id_valid( id ) ); return true; }
// if node_id is the last node, will return 0 // return; node_id int qdlink_next( int id, int node_id ){ uverify( id_valid( id ) ); uverify( node_id_valid( node_id ) ); node_t* const node = (node_t*)node_id; node_t* const p = node->next; // last node? if( (int)p == id ){ return 0; } return (int)p; }
// return: printf node num int qdlink_printf( int id, qdlink_node_printf_callback_t callback ){ uverify( id_valid( id ) ); if( NULL == callback ){ callback = node_printf_default; } printf( "\nqdlink<0x%08x>\n", id ); const int num = qdlink_for_each( id, qdlink_printf_callback, callback ); printf( "end(total %d)-------\n", num ); return true; }
// 把 batch 中的所有回调函数,依次执行 // 如果有一个返回false,只uverify()提示,依然执行后面的callback // return: all callback return true? // false, error & any callback return false bool batch_exec_close( int id ){ uverify( id_valid( id ) ); batch_t* const batch = (batch_t*)id; bool all_ok = true; int i = 0; for( i=0; i<batch->num; i++ ){ callback_arg_t* const p = &(batch->list[i]); if( !callback_arg_exec( p ) ){ all_ok = false; uverify( false ); } } return_false_if( !batch_close( id ) ); return all_ok; }
//typedef bool (*qdlink_for_eack_t)( int node_id, void* arg ); // return: loop time int qdlink_for_each( int id, qdlink_for_eack_t callback, void* arg ){ uverify( id_valid( id ) ); if( qdlink_empty( id ) ){ return 0; } node_t* const node = (node_t*)id; // p pointer to node node_t* p = NULL; int ix = 0; for( p=node; p->next!=node; p=p->next, ix++ ){ const int node_id = (int)(p->next); if( !callback( node_id, ix, arg ) ){ return ix + 1; } } return ix; }
// prev -> node // => // prev -> src -> node // return: ok? bool qdlink_insert( int id, int node_id, int node_src ){ uverify( id_valid( id ) ); uverify( node_id_valid( node_id ) ); uverify( node_id_valid( node_src ) ); int prev_id = 0; if( node_id == qdlink_first( id ) ){ prev_id = id; } else{ prev_id = qdlink_prev( id, node_id ); // not found the node uverify( 0 != prev_id ); } uverify( 0 != prev_id ); return_false_if( !qdlink_append( prev_id, node_src ) ); return true; }
// len: it's startup len, when batch list is full ,it will be auto growed up. // return: batch_id int batch_open( int len ){ uverify( 0 < len ); callback_arg_t* const list = qmalloc( len * sizeof( callback_arg_t ) ); return_0_if( NULL == list ); return_0_if( !init_list( list, len ) ); batch_t* const batch = qmalloc( sizeof( batch_t ) ); if( NULL == batch ){ qfree( list ); uverify( false ); return 0; } batch->list = list; batch->len = len; batch->num = 0; const int id = (int)batch; uverify( id_valid( id ) ); return id; }
// return: remove node num int qdlink_delete_all( int id ){ uverify( id_valid( id ) ); node_t* const node = (node_t*)id; // p pointer to node // q pointer to node->next node_t* p = NULL; node_t* q = NULL; int cnt = 0; for( p=node->next; p!=node; p=q, cnt++ ){ q = p->next; // 如果在调试状态,将指针清零,便于侦测到错误 if( GCFG_DEBUG_EN ){ memset( p, 0, sizeof( node_t ) ); } free( p ); } node->next = node; node->prev = node; return cnt; }
bool batch_id_valid( int id ){ return id_valid( id ); }
int qdlink_len( int id ){ uverify( id_valid( id ) ); const int loop_time = qdlink_for_each( id, qdlink_len_callback, NULL ); return loop_time; }