tb_void_t tb_vector_nremove(tb_vector_ref_t vector, tb_size_t itor, tb_size_t size) { // check tb_vector_impl_t* impl = (tb_vector_impl_t*)vector; tb_assert_and_check_return(impl && size && itor < impl->size); // clear it if (!itor && size >= impl->size) { tb_vector_clear(vector); return ; } // strip size if (itor + size > impl->size) size = impl->size - itor; // compute the left size tb_size_t left = impl->size - itor - size; // free data if (impl->func.nfree) impl->func.nfree(&impl->func, impl->data + itor * impl->func.size, size); // move the left data if (left) { tb_byte_t* pd = impl->data + itor * impl->func.size; tb_byte_t* ps = impl->data + (itor + size) * impl->func.size; tb_memmov(pd, ps, left * impl->func.size); } // update size impl->size -= size; }
tb_byte_t* tb_queue_buffer_push_init(tb_queue_buffer_ref_t buffer, tb_size_t* size) { // check tb_assert_and_check_return_val(buffer && buffer->maxn, tb_null); // no data? if (!buffer->data) { // make data buffer->data = tb_malloc_bytes(buffer->maxn); tb_assert_and_check_return_val(buffer->data, tb_null); // init buffer->head = buffer->data; buffer->size = 0; } tb_assert_and_check_return_val(buffer->data && buffer->head, tb_null); // full? tb_size_t left = buffer->maxn - buffer->size; tb_check_return_val(left, tb_null); // move data to head first, make sure there is enough write space if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // save size if (size) *size = left; // ok return buffer->head + buffer->size; }
static tb_void_t tb_hash_map_itor_remove(tb_iterator_ref_t iterator, tb_size_t itor) { // check tb_hash_map_impl_t* impl = (tb_hash_map_impl_t*)iterator; tb_assert_return(impl && impl->hash_list && impl->hash_size); // buck & item tb_size_t buck = tb_hash_map_index_buck(itor); tb_size_t item = tb_hash_map_index_item(itor); tb_assert_return(buck && item); buck--; item--; tb_assert_return(buck < impl->hash_size); // the step tb_size_t step = impl->element_name.size + impl->element_data.size; tb_assert_return(step); // get list tb_hash_map_item_list_t* list = impl->hash_list[buck]; tb_assert_return(list && list->size && item < list->size); // free item if (impl->element_name.free) impl->element_name.free(&impl->element_name, ((tb_byte_t*)&list[1]) + item * step); if (impl->element_data.free) impl->element_data.free(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size); // remove item from the list if (list->size > 1) { // move items if (item < list->size - 1) tb_memmov(((tb_byte_t*)&list[1]) + item * step, ((tb_byte_t*)&list[1]) + (item + 1) * step, (list->size - item - 1) * step); // update size list->size--; } // remove list else { // free it tb_free(list); // reset impl->hash_list[buck] = tb_null; } // update the impl item size impl->item_size--; }
tb_long_t tb_queue_buffer_writ(tb_queue_buffer_ref_t buffer, tb_byte_t const* data, tb_size_t size) { // check tb_assert_and_check_return_val(buffer && data && buffer->maxn, -1); // no data? if (!buffer->data) { // make data buffer->data = tb_malloc_bytes(buffer->maxn); tb_assert_and_check_return_val(buffer->data, -1); // init it buffer->head = buffer->data; buffer->size = 0; } tb_assert_and_check_return_val(buffer->data && buffer->head, -1); // full? tb_size_t left = buffer->maxn - buffer->size; tb_check_return_val(left, 0); // attempt to write data in tail directly if the tail space is enough tb_byte_t* tail = buffer->head + buffer->size; if (buffer->data + buffer->maxn >= tail + size) { tb_memcpy(tail, data, size); buffer->size += size; return (tb_long_t)size; } // move data to head if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // write data tb_size_t writ = left > size? size : left; tb_memcpy(buffer->data + buffer->size, data, writ); buffer->size += writ; // ok return writ; }
tb_void_t tb_vector_remove(tb_vector_ref_t vector, tb_size_t itor) { // check tb_vector_impl_t* impl = (tb_vector_impl_t*)vector; tb_assert_and_check_return(impl && itor < impl->size); if (impl->size) { // do free if (impl->func.free) impl->func.free(&impl->func, impl->data + itor * impl->func.size); // move data if itor is not last if (itor < impl->size - 1) tb_memmov(impl->data + itor * impl->func.size, impl->data + (itor + 1) * impl->func.size, (impl->size - itor - 1) * impl->func.size); // resize impl->size--; } }
tb_void_t tb_vector_ninsert_prev(tb_vector_ref_t vector, tb_size_t itor, tb_cpointer_t data, tb_size_t size) { // check tb_vector_impl_t* impl = (tb_vector_impl_t*)vector; tb_assert_and_check_return(impl && impl->data && size && itor <= impl->size); // save size tb_size_t osize = impl->size; // grow size if (!tb_vector_resize(vector, osize + size)) { tb_trace_d("impl resize: %u => %u failed", osize, osize + 1); return ; } // move items if not at tail if (osize != itor) tb_memmov(impl->data + (itor + size) * impl->func.size, impl->data + itor * impl->func.size, (osize - itor) * impl->func.size); // duplicate data impl->func.ndupl(&impl->func, impl->data + itor * impl->func.size, data, size); }
tb_byte_t* tb_buffer_memnmovp(tb_buffer_t* buffer, tb_size_t p, tb_size_t b, tb_size_t n) { // check tb_assert_and_check_return_val(buffer && (b + n) <= tb_buffer_size(buffer), tb_null); // clear? if (b == tb_buffer_size(buffer)) { tb_buffer_clear(buffer); return tb_buffer_data(buffer); } // check tb_check_return_val(p != b && n, tb_buffer_data(buffer)); // resize tb_byte_t* d = tb_buffer_resize(buffer, p + n); tb_assert_and_check_return_val(d, tb_null); // memmov tb_memmov(d + p, d + b, n); return d; }
tb_long_t tb_queue_buffer_writ(tb_queue_buffer_t* buffer, tb_byte_t const* data, tb_size_t size) { // check tb_assert_and_check_return_val(buffer && data && buffer->maxn, -1); // no data? if (!buffer->data) { // make data buffer->data = tb_malloc_bytes(buffer->maxn); tb_assert_and_check_return_val(buffer->data, -1); // init it buffer->head = buffer->data; buffer->size = 0; } tb_assert_and_check_return_val(buffer->data && buffer->head, -1); // no left? tb_size_t left = buffer->maxn - buffer->size; tb_check_return_val(left, 0); // move data to head if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // writ data tb_size_t writ = left > size? size : left; tb_memcpy(buffer->data + buffer->size, data, writ); buffer->size += writ; // ok return writ; }
tb_byte_t* tb_queue_buffer_resize(tb_queue_buffer_ref_t buffer, tb_size_t maxn) { // check tb_assert_and_check_return_val(buffer && maxn && maxn >= buffer->size, tb_null); // has data? if (buffer->data) { // move data to head if (buffer->head != buffer->data) { if (buffer->size) tb_memmov(buffer->data, buffer->head, buffer->size); buffer->head = buffer->data; } // realloc if (maxn > buffer->maxn) { // init head buffer->head = tb_null; // make data buffer->data = (tb_byte_t*)tb_ralloc(buffer->data, maxn); tb_assert_and_check_return_val(buffer->data, tb_null); // save head buffer->head = buffer->data; } } // update maxn buffer->maxn = maxn; // ok return buffer->data; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_size_t tb_path_translate(tb_char_t* path, tb_size_t size, tb_size_t maxn) { // check tb_assert_and_check_return_val(path, 0); // file://? tb_char_t* p = path; if (!tb_strnicmp(p, "file:", 5)) p += 5; // is user directory? else if (path[0] == '~') { // get the home directory tb_char_t home[TB_PATH_MAXN]; tb_size_t home_size = tb_directory_home(home, sizeof(home) - 1); tb_assert_and_check_return_val(home_size, 0); // check the path space tb_size_t path_size = size? size : tb_strlen(path); tb_assert_and_check_return_val(home_size + path_size - 1 < maxn, 0); // move the path and ensure the enough space for the home directory tb_memmov(path + home_size, path + 1, path_size - 1); // copy the home directory tb_memcpy(path, home, home_size); path[home_size + path_size - 1] = '\0'; } // remove repeat separator tb_char_t* q = path; tb_size_t repeat = 0; for (; *p; p++) { if (tb_path_is_separator(*p)) { // save the separator if not exists if (!repeat) *q++ = TB_PATH_SEPARATOR; // repeat it repeat++; } else { // save character *q++ = *p; // clear repeat repeat = 0; } } // remove the tail separator and not root: '/' if (q > path + 1 && *(q - 1) == TB_PATH_SEPARATOR) q--; // end *q = '\0'; // is windows path? if (q > path + 1 && tb_isalpha(path[0]) && path[1] == ':') { // get the upper drive prefix path[0] = tb_toupper(path[0]); // append the drive separator if not exists if (q - path == 2) { *q++ = TB_PATH_SEPARATOR; *q = '\0'; } } // trace tb_trace_d("translate: %s", path); // ok return q - path; }
tb_size_t tb_hash_map_insert(tb_hash_map_ref_t hash_map, tb_cpointer_t name, tb_cpointer_t data) { // check tb_hash_map_impl_t* impl = (tb_hash_map_impl_t*)hash_map; tb_assert_and_check_return_val(impl, 0); // the step tb_size_t step = impl->element_name.size + impl->element_data.size; tb_assert_and_check_return_val(step, 0); // find it tb_size_t buck = 0; tb_size_t item = 0; if (tb_hash_map_item_find(impl, name, &buck, &item)) { // check tb_assert_and_check_return_val(buck < impl->hash_size, 0); // get list tb_hash_map_item_list_t* list = impl->hash_list[buck]; tb_assert_and_check_return_val(list && list->size && item < list->size, 0); // replace data impl->element_data.repl(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size, data); } else { // check tb_assert_and_check_return_val(buck < impl->hash_size, 0); // get list tb_hash_map_item_list_t* list = impl->hash_list[buck]; // insert item if (list) { // grow? if (list->size >= list->maxn) { // check tb_assert_and_check_return_val(impl->item_grow, 0); // resize maxn tb_size_t maxn = tb_align_pow2(list->maxn + impl->item_grow); tb_assert_and_check_return_val(maxn > list->maxn, 0); // realloc it list = (tb_hash_map_item_list_t*)tb_ralloc(list, sizeof(tb_hash_map_item_list_t) + maxn * step); tb_assert_and_check_return_val(list, 0); // update the impl item maxn impl->item_maxn += maxn - list->maxn; // update maxn list->maxn = maxn; // reattach list impl->hash_list[buck] = list; } tb_assert_and_check_return_val(item <= list->size && list->size < list->maxn, 0); // move items if (item != list->size) tb_memmov(((tb_byte_t*)&list[1]) + (item + 1) * step, ((tb_byte_t*)&list[1]) + item * step, (list->size - item) * step); // dupl item list->size++; impl->element_name.dupl(&impl->element_name, ((tb_byte_t*)&list[1]) + item * step, name); impl->element_data.dupl(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size, data); } // create list for adding item else { // check tb_assert_and_check_return_val(impl->item_grow, 0); // make list list = (tb_hash_map_item_list_t*)tb_malloc0(sizeof(tb_hash_map_item_list_t) + impl->item_grow * step); tb_assert_and_check_return_val(list, 0); // init list list->size = 1; list->maxn = impl->item_grow; impl->element_name.dupl(&impl->element_name, ((tb_byte_t*)&list[1]), name); impl->element_data.dupl(&impl->element_data, ((tb_byte_t*)&list[1]) + impl->element_name.size, data); // attach list impl->hash_list[buck] = list; // update the impl item maxn impl->item_maxn += list->maxn; } // update the impl item size impl->item_size++; } // ok? return tb_hash_map_index_make(buck + 1, item + 1); }
static tb_void_t tb_hash_map_itor_remove_range(tb_iterator_ref_t iterator, tb_size_t prev, tb_size_t next, tb_size_t size) { // check tb_hash_map_impl_t* impl = (tb_hash_map_impl_t*)iterator; tb_assert_return(impl && impl->hash_list && impl->hash_size); // no size tb_check_return(size); // the step tb_size_t step = impl->element_name.size + impl->element_data.size; tb_assert_return(step); // the first itor tb_size_t itor = prev? tb_hash_map_itor_next(iterator, prev) : tb_hash_map_itor_head(iterator); // the head buck and item tb_size_t buck_head = tb_hash_map_index_buck(itor); tb_size_t item_head = tb_hash_map_index_item(itor); tb_assert_return(buck_head && item_head); // compute index buck_head--; item_head--; tb_assert_return(buck_head < impl->hash_size && item_head < TB_HASH_MAP_BUCKET_ITEM_MAXN); // the last buck and the tail item tb_size_t buck_last; tb_size_t item_tail; if (next) { // next => buck and item buck_last = tb_hash_map_index_buck(next); item_tail = tb_hash_map_index_item(next); tb_assert_return(buck_last && item_tail); // compute index buck_last--; item_tail--; tb_assert_return(buck_last < impl->hash_size && item_tail < TB_HASH_MAP_BUCKET_ITEM_MAXN); } else { buck_last = impl->hash_size - 1; item_tail = -1; } // remove items: [itor, next) tb_size_t buck; tb_size_t item; tb_element_free_func_t name_free = impl->element_name.free; tb_element_free_func_t data_free = impl->element_data.free; for (buck = buck_head, item = item_head; buck <= buck_last; buck++, item = 0) { // the list tb_hash_map_item_list_t* list = impl->hash_list[buck]; tb_check_continue(list && list->size); // the tail tb_size_t tail = (buck == buck_last && next)? item_tail : list->size; tb_assert_abort(tail != -1); tb_check_continue(item < tail); // the data tb_byte_t* data = (tb_byte_t*)&list[1]; // free items tb_size_t i = 0; for (i = item; i < tail; i++) { if (name_free) name_free(&impl->element_name, data + i * step); if (data_free) data_free(&impl->element_data, data + i * step + impl->element_name.size); } // move items if (buck == buck_last && tail < list->size) tb_memmov(data + item * step, data + tail * step, (list->size - tail) * step); // update the list size list->size -= tail - item; // update the item size impl->item_size -= tail - item; } }