Skip to content

Commit

Permalink
Cập nhật tài liệu map
Browse files Browse the repository at this point in the history
  • Loading branch information
bangoc committed Jan 14, 2022
1 parent 15614c2 commit 3b0ea1f
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 83 deletions.
64 changes: 45 additions & 19 deletions hmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* hmap_create(gtype_hash_t hash_func, gtype_cmp_t cmp, gtype_free_t free_key, gtype_free_t free_value)
*
* Các macro hỗ trợ:
* #hmap_size(map) - Kích thước của map
* #hmap_traverse(k, v, map) - Duyệt tuần tự các cặp trong map.
*
*/
Expand Down Expand Up @@ -89,54 +90,49 @@ hmap_t hmap_create(gtype_hash_t hash_func, gtype_cmp_t cmp,

/**
* Thêm cặp (key, value) vào bảng tab. Nếu key đã tồn tại thì
* bỏ qua, có thể truy cập giá trị gắn với khóa đã có trong
* bảng băm theo đối tượng ::hmap_ires được trả về.
* bỏ qua, có thể truy cập giá trị đang được gắn với khóa đã có
* trong bảng băm bằng con trỏ ::hmap_ires::value trong kết quả
* được trả về.
*
* @param tab Con trỏ tới bảng băm
* @param key Khóa
* @param value Giá trị
* @param key Khóa được thêm vào
* @param value Giá trị giá trị được thêm vào
* @return Trả về đối tượng ::hmap_ires
*
* \memberof hash_map_s
*
* Tham khảo: rbm_insert(rbm_t t, gtype key, gtype value)
*/
hmap_ires hmap_insert(hmap_t tab, gtype key, gtype value);

/**
* Tra cứu giá trị trong bảng tab theo key.
*
* @param tab Con trỏ tới bảng băm.
* @param key Khóa
* @param key Khóa được sử dụng để tìm kiếm.
* @return Trả về con trỏ tới giá trị đang được gắn với key trong tab
* nếu tồn tại, hoặc NULL nếu ngược lại.
*
* \memberof hash_map_s
*
* Tham khảo: rbm_value(rbm_t t, gtype key)
*/
gtype *hmap_value(hmap_t tab, gtype key);

/**
* Nếu key không có trong tab thì không làm gì, nếu ngược lại thì xóa cặp
* Nếu key không có trong tab thì bỏ qua, nếu ngược lại thì xóa cặp
* khóa & giá trị tương ứng trong tab. Các hàm free_key và free_value được
* gọi nếu != NULL.
*
* @param tab Con trỏ tới bảng băm
* @param key Khóa cần xóa.
* @return 1 nếu tồn tại khóa, 0 nếu ngược lại.
* @return 1 Nếu tồn tại khóa sau khi xóa dữ liệu, 0 nếu ngược lại.
*
* \memberof hash_map_s
*/
int hmap_remove(hmap_t tab, gtype key);
void hmap_clear(hmap_t tab);

/**
* Giải phóng bộ nhớ được cấp phát cho bảng băm tab. Các hàm free_key và
* free_value được gọi cho từng khóa và từng giá trị nếu != NULL.
*
* @param tab Con trỏ tới bảng băm.
* @return Hàm không trả về giá trị.
*
* \memberof hash_map_s
* Tham khảo: rbm_remove(rbm_t t, gtype key)
*/
void hmap_free(hmap_t tab);
int hmap_remove(hmap_t tab, gtype key);

/**
* Số lượng cặp khóa & giá trị đang được lưu trong hmap.
Expand All @@ -147,6 +143,34 @@ void hmap_free(hmap_t tab);
*/
#define hmap_size(tab) (tab->size)

/**
* Giải phóng bộ nhớ được cấp phát cho bảng băm tab. Các hàm free_key và
* free_value được gọi cho từng khóa và từng giá trị nếu != NULL.
*
* @param tab Con trỏ tới bảng băm.
*/
#define hmap_free(tab) \
do { \
int _capacity = (tab)->capacity; \
gtype *_keys = ARR((tab)->keys); \
gtype *_values = ARR((tab)->values); \
uint *_hashes = ARR((tab)->hashes); \
for (int _i = 0; _i < _capacity; ++_i) { \
if (HASH_IS_REAL(_hashes[_i])) { \
if ((tab)->free_key) { \
(tab)->free_key(_keys[_i]); \
} \
if ((tab)->free_value) { \
(tab)->free_value(_values[_i]); \
} \
} \
} \
arr_free((tab)->keys); \
arr_free((tab)->values); \
arr_free((tab)->hashes); \
free(tab); \
} while (0)

gtype *hmap_next_pkey(hmap_t, gtype*);
gtype *hmap_next_pvalue(hmap_t, gtype*);

Expand All @@ -157,6 +181,8 @@ gtype *hmap_next_pvalue(hmap_t, gtype*);
* @param key Định danh sẽ được sử dụng như con trỏ tới khóa.
* @param value Định danh sẽ được sử dụng như giá trị tới khóa.
* @param map Con trỏ tới bảng băm.
*
* Tham khảo: #rbm_traverse(k, v, map)
*/
#define hmap_traverse(key, value, map) \
for(gtype *key = hmap_next_pkey(map, NULL), *value = hmap_next_pvalue(map, NULL); \
Expand Down
106 changes: 87 additions & 19 deletions rbm.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ typedef struct rbm_node {
* Cấu trúc điều khiển của bảng cây rbm, được tạo bằng hàm
* rbm_create(gtype_cmp_t cmp, gtype_free_t free_key, gtype_free_t free_value).
*
* Các macro hỗ trợ: <br>
* #rbm_size(t) - Kích thước của t.
* #rbm_traverse(k, v, t) - Duyệt tuần tự các cặp trong t.
*/
typedef struct rbm_s {
struct bn_tree t;
Expand Down Expand Up @@ -76,28 +79,62 @@ rbm_node_t rbm_create_node(gtype key, gtype value);
rbm_t rbm_create(gtype_cmp_t cmp,
gtype_free_t free_key, gtype_free_t free_value);

/**
* Thêm cặp (key, value) vào bảng t. Nếu key đã tồn tại thì
* bỏ qua, có thể truy cập giá trị đang được gắn với khóa
* đã có trong t bằng con trỏ ::rbm_ires::value trong kết quả
* được trả về.
*
* @param t Con trỏ tới bảng cây.
* @param key Khóa được thêm vào.
* @param value Giá trị được thêm vào.
* @return Trả về đối tượng ::rbm_ires
*
* \memberof rbm_s
*
* Tham khảo: hmap_insert(hmap_t tab, gtype key, gtype value)
*/
rbm_ires rbm_insert(rbm_t t, gtype key, gtype value);
gtype *rbm_vref(rbm_t t, gtype key);

/**
* Tra cứu giá trị trong t theo key.
*
* @param t Con trỏ tới đối tượng bảng cây.
* @param key Khóa được sử dụng để tìm kiếm.
* @return Trả về con trỏ tới giá trị đang được gắn với key trong t
* nếu tồn tại, hoặc NULL nếu ngược lại.
*
* \memberof rbm_s
*
* Tham khảo: hmap_value(hmap_t tab, gtype key)
*/
gtype *rbm_value(rbm_t t, gtype key);
rbm_node_t rbm_search(rbm_t t, gtype key);

/**
* Nếu key không có trong t thì bỏ qua, nếu ngược lại thì xóa cặp
* khóa & giá trị tương ứng trong t. Các hàm free_key và free_value
* được gọi nếu != NULL.
*
* @param t Con trỏ tới bảng cây.
* @param key Khóa cần xóa.
* @return 1 Nếu tồn tại khóa sau khi xóa dữ liệu, 0 nếu ngược lại.
*
* \memberof rbm_s
*
* Tham khảo: hmap_remove(hmap_t tab, gtype key)
*/
int rbm_remove(rbm_t t, gtype key);

/**
* Số lượng cặp khóa & giá trị đang được lưu trong bảng.
*
* @param t Con trỏ tới đối tượng bảng cây.
* @return Trả về số lượng cặp khóa/giá trị đang được lưu trong t.
*
*/
#define rbm_size(t) (bn_size((bn_tree_t)s))

#define rbm_free(m) \
do { \
if ((m)->free_key || (m)->free_value) { \
rbm_traverse(_k, _v, (m)) { \
if ((m)->free_key) { \
(m)->free_key(*_k); \
} \
if ((m)->free_value) { \
(m)->free_value(*_v); \
} \
} \
} \
bn_free_tree((bn_tree_t)(m)); \
} while (0)

static inline void _rbm_move_next(gtype **k, gtype **v) {
rbm_node_t nd = container_of(*k, struct rbm_node, key);
bn_node_t tmp = bn_next_inorder(to_bn(nd));
Expand All @@ -110,9 +147,40 @@ static inline void _rbm_move_next(gtype **k, gtype **v) {
*v = &(rbm_node_value(tmp));
}

#define rbm_traverse(k, v, m) \
for (gtype *k = &(rbm_node_key(bn_left_most((m)->t.root))), \
*v = &(rbm_node_value(bn_left_most((m)->t.root))); \
/**
* Duyệt tuần tự các cặp khóa & giá trị trong bảng map. Các tham số k và v
* là các định danh do người sử dụng tự đặt và sẽ có kiểu ::gtype *
*
* @param k Định danh sẽ được sử dụng như con trỏ tới khóa hiện hành.
* @param v Định danh sẽ được sử dụng như con trỏ tới giá trị hiện hành.
* @param map Con trỏ tới bảng cây.
*
* Tham khảo: #hmap_traverse(key, value, map)
*/
#define rbm_traverse(k, v, map) \
for (gtype *k = &(rbm_node_key(bn_left_most((map)->t.root))), \
*v = &(rbm_node_value(bn_left_most((map)->t.root))); \
k != NULL_PTR && v != NULL_PTR; _rbm_move_next(&k, &v)) \

/**
* Giải phóng bộ nhớ được cấp phát cho bảng m. Các hàm free_key và
* free_value được gọi cho từng khóa và giá trị nếu != NULL.
*
* @param t Con trỏ tới bảng cây.
*/
#define rbm_free(t) \
do { \
if ((t)->free_key || (t)->free_value) { \
rbm_traverse(_k, _v, (t)) { \
if ((t)->free_key) { \
(t)->free_key(*_k); \
} \
if ((t)->free_value) { \
(t)->free_value(*_v); \
} \
} \
} \
bn_free_tree((bn_tree_t)(t)); \
} while (0)

#endif // RBM_H_
36 changes: 1 addition & 35 deletions src/hmap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
(C) Nguyen Ba Ngoc 2o21
(C) Nguyen Ba Ngoc 2021
*/

#include "hmap.h"
Expand All @@ -11,7 +11,6 @@ static void hmap_setup_storage(hmap_t tab);
static inline int hmap_lookup_node(hmap_t tab, gtype key, uint *hash_return);
static inline int hmap_maybe_realloc(hmap_t tab);
static void hmap_remove_node(hmap_t tab, int i);
static void hmap_free_nodes(hmap_t tab);

hmap_t hmap_create(gtype_hash_t hash_func, gtype_cmp_t cmp,
gtype_free_t free_key, gtype_free_t free_value) {
Expand Down Expand Up @@ -66,16 +65,6 @@ int hmap_remove(hmap_t tab, gtype key) {
return 1;
}

void hmap_clear(hmap_t tab) {
hmap_free_nodes(tab);
hmap_setup_storage(tab);
}

void hmap_free(hmap_t tab) {
hmap_free_nodes(tab);
free(tab);
}

gtype *hmap_next_pkey(hmap_t map, gtype* curr) {
gtype * r;
hashes_next_pkey_or_pvalue(map, curr, keys, r);
Expand Down Expand Up @@ -164,29 +153,6 @@ static void hmap_remove_node(hmap_t tab, int i) {
}
}

static void hmap_free_nodes(hmap_t tab) {
int capacity = tab->capacity;
gtype *keys = ARR(tab->keys);
gtype *values = ARR(tab->values);
uint *hashes = ARR(tab->hashes);
for (int i = 0; i < capacity; ++i) {
if (HASH_IS_REAL(hashes[i])) {
if (tab->free_key) {
tab->free_key(keys[i]);
}
if (tab->free_value) {
tab->free_value(values[i]);
}
}
}
arr_free(tab->keys);
arr_free(tab->values);
arr_free(tab->hashes);

tab->size = 0;
tab->noccupied = 0;
}

static void hmap_realloc_arrays(hmap_t tab) {
arr_set_capacity(tab->hashes, tab->capacity);
arr_set_capacity(tab->keys, tab->capacity);
Expand Down
2 changes: 1 addition & 1 deletion src/rbm.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ rbm_node_t rbm_search(rbm_t t, gtype key) {
bns_search_inline(n, ((bn_tree_t)t), key, tm_cmp_conv, return to_rbm(n));
}

gtype *rbm_vref(rbm_t t, gtype key) {
gtype *rbm_value(rbm_t t, gtype key) {
rbm_node_t n = rbm_search(t, key);
if (n) {
return &n->value;
Expand Down
18 changes: 9 additions & 9 deletions tests/gttreemap/gt_treemap_ut.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@ int main() {
rbm_insert(t, gtype_s(sd), gtype_s(s5));
rbm_insert(t, gtype_s(se), gtype_s(s6));
rbm_insert(t, gtype_s(sf), gtype_s(s7));
CHECK_MSG(strcmp(rbm_vref(t, gtype_s(sa))->s, s1) == 0, "Failed A Value");
CHECK_MSG(strcmp(rbm_vref(t, gtype_s(sb))->s, s2) == 0, "Failed B Value");
CHECK_MSG(strcmp(rbm_vref(t, gtype_s(sc))->s, s3) == 0, "Failed C Value");
CHECK_MSG(strcmp(rbm_vref(t, gtype_s(sd))->s, s5) == 0, "Failed D Value");
CHECK_MSG(strcmp(rbm_vref(t, gtype_s(se))->s, s6) == 0, "Failed E Value");
CHECK_MSG(strcmp(rbm_vref(t, gtype_s(sf))->s, s7) == 0, "Failed F Value");
CHECK_MSG(strcmp(rbm_value(t, gtype_s(sa))->s, s1) == 0, "Failed A Value");
CHECK_MSG(strcmp(rbm_value(t, gtype_s(sb))->s, s2) == 0, "Failed B Value");
CHECK_MSG(strcmp(rbm_value(t, gtype_s(sc))->s, s3) == 0, "Failed C Value");
CHECK_MSG(strcmp(rbm_value(t, gtype_s(sd))->s, s5) == 0, "Failed D Value");
CHECK_MSG(strcmp(rbm_value(t, gtype_s(se))->s, s6) == 0, "Failed E Value");
CHECK_MSG(strcmp(rbm_value(t, gtype_s(sf))->s, s7) == 0, "Failed F Value");
CHECK_MSG(rbm_remove(t, gtype_s(sd)) == 1, "remove sd");
CHECK_MSG(rbm_remove(t, gtype_s(se)) == 1, "remove se");
CHECK_MSG(rbm_remove(t, gtype_s(sf)) == 1, "remove sf");
gtype *value = NULL_PTR, query = {.s = sd};
CHECK_MSG(rbm_vref(t, query) == NULL_PTR, "Failed not found D");
CHECK_MSG(rbm_value(t, query) == NULL_PTR, "Failed not found D");
query = gtype_s(se);
CHECK_MSG(rbm_vref(t, query) == NULL_PTR, "Failed not found E");
CHECK_MSG(rbm_value(t, query) == NULL_PTR, "Failed not found E");
query = gtype_s(sf);
CHECK_MSG(rbm_vref(t, query) == NULL_PTR, "Failed not found F");
CHECK_MSG(rbm_value(t, query) == NULL_PTR, "Failed not found F");
bn_free_tree((bn_tree_t)t);
printf("Treemap ut OK\n");
return 0;
Expand Down

0 comments on commit 3b0ea1f

Please sign in to comment.