/* ////////////////////////////////////////////////////////////////////////////////////// * malloc implementation */ static __tb_inline__ tb_size_t tb_static_large_allocator_pred_index(tb_static_large_allocator_ref_t allocator, tb_size_t space) { #ifndef TB_CONFIG_MICRO_ENABLE // the size tb_size_t size = sizeof(tb_static_large_data_head_t) + space; tb_assert(!(size & (allocator->page_size - 1))); // the page count size /= allocator->page_size; // the pred index #if 0 tb_size_t indx = tb_ilog2i(tb_align_pow2(size)); #else // faster tb_size_t indx = size > 1? (tb_ilog2i((tb_uint32_t)(size - 1)) + 1) : 0; #endif if (indx >= tb_arrayn(allocator->data_pred)) indx = tb_arrayn(allocator->data_pred) - 1; return indx; #else return 0; #endif }
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); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_hash_map_ref_t tb_hash_map_init(tb_size_t bucket_size, tb_element_t element_name, tb_element_t element_data) { // check tb_assert_and_check_return_val(element_name.size && element_name.hash && element_name.comp && element_name.data && element_name.dupl, tb_null); tb_assert_and_check_return_val(element_data.data && element_data.dupl && element_data.repl, tb_null); // check bucket size if (!bucket_size) bucket_size = TB_HASH_MAP_BUCKET_SIZE_DEFAULT; tb_assert_and_check_return_val(bucket_size <= TB_HASH_MAP_BUCKET_SIZE_LARGE, tb_null); // done tb_bool_t ok = tb_false; tb_hash_map_impl_t* impl = tb_null; do { // make hash_map impl = tb_malloc0_type(tb_hash_map_impl_t); tb_assert_and_check_break(impl); // init hash_map func impl->element_name = element_name; impl->element_data = element_data; // init item itor impl->itor.mode = TB_ITERATOR_MODE_FORWARD | TB_ITERATOR_MODE_MUTABLE; impl->itor.priv = tb_null; impl->itor.step = sizeof(tb_hash_map_item_t); impl->itor.size = tb_hash_map_itor_size; impl->itor.head = tb_hash_map_itor_head; impl->itor.tail = tb_hash_map_itor_tail; impl->itor.prev = tb_null; impl->itor.next = tb_hash_map_itor_next; impl->itor.item = tb_hash_map_itor_item; impl->itor.copy = tb_hash_map_itor_copy; impl->itor.comp = tb_hash_map_itor_comp; impl->itor.remove = tb_hash_map_itor_remove; impl->itor.remove_range = tb_hash_map_itor_remove_range; // init hash_map size impl->hash_size = tb_align_pow2(bucket_size); tb_assert_and_check_break(impl->hash_size <= TB_HASH_MAP_BUCKET_MAXN); // init hash_map list impl->hash_list = (tb_hash_map_item_list_t**)tb_nalloc0(impl->hash_size, sizeof(tb_size_t)); tb_assert_and_check_break(impl->hash_list); // init item grow impl->item_grow = tb_isqrti(bucket_size); if (impl->item_grow < 8) impl->item_grow = 8; impl->item_grow = tb_align_pow2(impl->item_grow); // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (impl) tb_hash_map_exit((tb_hash_map_ref_t)impl); impl = tb_null; } // ok? return (tb_hash_map_ref_t)impl; }