uthash版本 :2.0.2
作者:jafon.tian
转载请注明出处:https://blog.csdn.net/JT_Notes
为了能直观的看到hash表的情况,下面提供一种将hash表详情打印到标准输出或文件的方式。
名称 | 参数 |
---|---|
PRINT_UTHASH | (head) 基于PRINT_UTHASH_HH的宏 |
PRINT_UTHASH_HH | (hh, head) hh为句柄成员名称 head为hash表指针 |
在包含printHashTable.h之前定义PRINT_FILE_ENABLE使能输出到文件,通过PRINT_FILE_FULLPATH定义文件全路径,缺省输出到”/tmp/print_uthash_table.txt”。
#include "uthash.h"
#include
#include /* malloc */
#include /* printf */
//使能打印到文件 !!!
#define PRINT_FILE_ENABLE
//指定打印文件全路径,默认路径是"/tmp/print_uthash_table.txt" !!!
#define PRINT_FILE_FULLPATH "./print_uthash_table.txt"
#include "printHashTable.h"
//添加头文件 !!!
#include "printHashTable.h"
typedef struct example_user_t {
int id;
int cookie;
UT_hash_handle hh;
} example_user_t;
int main(int argc,char *argv[])
{
int i;
example_user_t *user, *tmp, *users=NULL;
// 打印hash表 !!!
PRINT_UTHASH(users);
/* create elements */
for(i=0; i<10; i++) {
user = (example_user_t*)malloc(sizeof(example_user_t));
if (user == NULL) {
exit(-1);
}
user->id = i;
user->cookie = i*i;
HASH_ADD_INT(users,id,user);
}
// 打印hash表 !!!
PRINT_UTHASH(users);
/* find each even ID */
for(i=0; i<10; i+=2) {
HASH_FIND_INT(users,&i,tmp);
if (tmp != NULL) {
printf("user id %d found, cookie %d\n", tmp->id, tmp->cookie);
} else {
printf("user id %d not found\n", i);
}
}
return 0;
}
输出如下内容
invalid arg head
PRINT_UTHASH fail, ret = -100
============================================== TABLE INFORMATION ==============================================
Address ideal num_buckets log2_num_buckets num_items hho ideal_cmax nonideal_items ineff_ex noex overhead
---------- ----- ----------- ---------------- --------- ---- ---------- -------------- -------- ---- ----------
0x1338060 100% 32 5 10 8 0 0 ok ok 1136
************** BUCKET( 1) INFORMATION : Address:0x13380c0 count:1 expand_mult:0
hashv:74401341 | key:9 | keylen: 4
************** BUCKET( 4) INFORMATION : Address:0x13380f0 count:1 expand_mult:0
hashv:B68EF0E4 | key:3 | keylen: 4
************** BUCKET( 5) INFORMATION : Address:0x1338100 count:3 expand_mult:0
hashv:0DB3B8E5 | key:4 | keylen: 4 <===>
hashv:6217F7A5 | key:1 | keylen: 4 <===>
hashv:2A333225 | key:0 | keylen: 4
************** BUCKET( 14) INFORMATION : Address:0x1338190 count:1 expand_mult:0
hashv:45F2400E | key:6 | keylen: 4
************** BUCKET( 17) INFORMATION : Address:0x13381c0 count:1 expand_mult:0
hashv:46FD8A31 | key:5 | keylen: 4
************** BUCKET( 18) INFORMATION : Address:0x13381d0 count:1 expand_mult:0
hashv:9D13C292 | key:8 | keylen: 4
************** BUCKET( 26) INFORMATION : Address:0x1338250 count:1 expand_mult:0
hashv:B33656FA | key:7 | keylen: 4
************** BUCKET( 28) INFORMATION : Address:0x1338270 count:1 expand_mult:0
hashv:6392F77C | key:2 | keylen: 4
/*
Copyright (c) 2018, jafon.tian https://blog.csdn.net/JT_Notes
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PRINT_HASH_TABLE__
#define __PRINT_HASH_TABLE__
#include "uthash.h"
#ifdef PRINT_FILE_ENABLE
#define P_TO_FILE // enable print table to file, undefine this to enable print to stdout
#endif
#ifdef PRINT_FILE_FULLPATH
#define DEFAULT_FILE PRINT_FILE_FULLPATH
#else
#define DEFAULT_FILE "/tmp/print_uthash_table.txt"
#endif
#ifdef P_TO_FILE
static FILE *_g_printfile = NULL;
#define PRINT_START(filename, ret) \
do \
{ \
_g_printfile = fopen(filename, "a"); \
if (!_g_printfile) \
{ \
printf("open file \"%s\" fail\n", DEFAULT_FILE); \
ret = -1; \
} \
} while (0)
#define PRINT_END() \
do \
{ \
if (_g_printfile) \
{ \
fclose(_g_printfile); \
} \
} while (0)
#define PRINT_INFO(...) \
do \
{ \
if (_g_printfile) \
{ \
fprintf(_g_printfile, __VA_ARGS__); \
} \
} while (0)
#else
#define PRINT_START(filename, ret)
#define PRINT_END()
#define PRINT_INFO(...) \
do \
{ \
printf(__VA_ARGS__); \
} while (0)
#endif
#define PRINT_RET(ret) \
if (ret) \
break
/*
============================================== TABLE INFORMATION ==============================================
Address ideal num_buckets log2_num_buckets num_items hho ideal_cmax nonideal_items ineff_ex noex overhead
---------- ----- ----------- ---------------- --------- ---- ---------- -------------- -------- ---- ----------
0x1338060 100% 32 5 10 8 0 0 ok ok 1136
*/
#define PRINT_TABLE_HH(hh, head, ret) \
do \
{ \
int inx; \
UT_hash_table *tbl = NULL; \
size_t overhead; \
if (!head) \
{ \
PRINT_INFO("invalid arg head \n"); \
ret = -100; \
PRINT_RET(ret); \
} \
tbl = head->hh.tbl; \
if (!tbl) \
{ \
PRINT_INFO("invalid arg tbl \n"); \
ret = -200; \
PRINT_RET(ret); \
} \
overhead = HASH_OVERHEAD(hh, head); \
PRINT_INFO("============================================== TABLE INFORMATION ==============================================\n"); \
PRINT_INFO("Address ideal num_buckets log2_num_buckets num_items hho ideal_cmax nonideal_items ineff_ex noex overhead \n"); \
PRINT_INFO("---------- ----- ----------- ---------------- --------- ---- ---------- -------------- -------- ---- ----------\n"); \
PRINT_INFO("%-10p %4.0f%% %11u %16u %9u %4u %10u %14u %8s %4s %-10u\n\n", \
(void *)tbl, \
(tbl->num_items - tbl->nonideal_items) * 100.0 / tbl->num_items, \
tbl->num_buckets, \
tbl->log2_num_buckets, \
tbl->num_items, \
tbl->hho, \
tbl->ideal_chain_maxlen, \
tbl->nonideal_items, \
tbl->ineff_expands ? "IE" : "ok", \
tbl->noexpand ? "NX" : "ok", \
overhead); \
for (inx = 0; inx < tbl->num_buckets; inx++) \
{ \
PRINT_BUCKET(&tbl->buckets[inx], inx, ret); \
PRINT_RET(ret); \
} \
PRINT_RET(ret); \
} while (0)
/*
************** BUCKET( 1) INFORMATION : Address:0x13380c0 count:1 expand_mult:0
*/
#define PRINT_BUCKET(bkt_in, inx, ret) \
do \
{ \
UT_hash_bucket *bkt = bkt_in; \
UT_hash_handle *lhh; \
if (!bkt) \
{ \
PRINT_INFO("invalid bucket\n"); \
ret = -200; \
PRINT_RET(ret); \
} \
if (bkt->count) \
{ \
PRINT_INFO("************** BUCKET(%6u) INFORMATION : Address:%-18p count:%-15u expand_mult:%-11u\n", \
inx, \
(void *)bkt, \
bkt->count, \
bkt->expand_mult); \
lhh = bkt->hh_head; \
while (lhh) \
{ \
PRINT_HH(lhh, ret); \
PRINT_RET(ret); \
lhh = lhh->hh_next; \
} \
PRINT_RET(ret); \
PRINT_INFO("\n"); \
} \
} while (0)
/*
hashv:0DB3B8E5 | key:4 | keylen: 4 <===>
hashv:6217F7A5 | key:1 | keylen: 4 <===>
hashv:2A333225 | key:0 | keylen: 4
*/
#define PRINT_HH(hh, ret) \
do \
{ \
if (!hh) \
{ \
PRINT_INFO("invalid hash handle\n"); \
ret = -300; \
PRINT_RET(ret); \
} \
if (hh->keylen == sizeof(int)) \
PRINT_INFO("hashv:%08X | key:%-9X | keylen:%4u", hh->hashv, *((int *)hh->key), hh->keylen); \
else \
PRINT_INFO("hashv:%08X | key:%-9s | keylen:%4u", hh->hashv, (const char *)hh->key, hh->keylen); \
if (hh->hh_next) \
PRINT_INFO(" <===> "); \
PRINT_INFO("\n"); \
} while (0)
#define PRINT_UTHASH_HH(hh, head) \
do \
{ \
int ret = 0; \
UT_hash_table *tbl = NULL; \
UT_hash_bucket *brks = NULL; \
PRINT_START(DEFAULT_FILE, ret); \
do \
{ \
PRINT_RET(ret); \
PRINT_TABLE_HH(hh, head, ret); \
} while (0); \
if (ret) \
PRINT_INFO("PRINT_UTHASH fail, ret = %d\n", ret); \
PRINT_END(); \
} while (0)
#define PRINT_UTHASH(head) PRINT_UTHASH_HH(hh, head)
#endif