1.0.0-dev #4
| @@ -66,7 +66,7 @@ Logger *newLogger(const char *name); | ||||
|  */ | ||||
| Logger *getDefaultLogger(void); | ||||
|  | ||||
| Logger *getLogger(const char *name, log_level level); | ||||
| Logger *getLogger(const char *name); | ||||
|  | ||||
| /** | ||||
|  * @brief 销毁日志对象,该方法会销毁默认日志对象 | ||||
|   | ||||
| @@ -21,6 +21,8 @@ | ||||
|  | ||||
| static Logger *ROOT_LOGGER = NULL; // 根日志对象,唯一实例 | ||||
|  | ||||
| static Map *LOGGER_MAP     = NULL; // 日志对象映射表 | ||||
|  | ||||
| /** | ||||
|  * @brief 为日志添加一个handler | ||||
|  * @param handler 处理器对象 | ||||
| @@ -201,11 +203,17 @@ Logger *newLogger(const char *name) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (LOGGER_MAP == NULL) { | ||||
|         LOGGER_MAP = map_create(sizeof(Logger **)); | ||||
|     } | ||||
|  | ||||
|     logger->level   = LOG_INFO; | ||||
|     logger->handler = loggingHandlerConsole(); | ||||
|     logger->name    = name; | ||||
|     logger->filter  = NULL; | ||||
|  | ||||
|     map_put(LOGGER_MAP, name, &logger); | ||||
|  | ||||
|     return logger; | ||||
| } | ||||
|  | ||||
| @@ -224,18 +232,28 @@ Logger *getDefaultLogger(void) { | ||||
|  * @param level 日志等级 | ||||
|  * @return 日志器对象 | ||||
|  */ | ||||
| Logger *getLogger(const char *name, log_level level) { | ||||
| Logger *getLogger(const char *name) { | ||||
|     if (name == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (LOGGER_MAP == NULL) { | ||||
|         LOGGER_MAP = map_create(sizeof(Logger **)); | ||||
|     } | ||||
|  | ||||
|     Logger **cache_logger_ptr = (Logger **)map_get(LOGGER_MAP, name); | ||||
|     if (cache_logger_ptr != NULL) { | ||||
|         return *cache_logger_ptr; | ||||
|     } | ||||
|  | ||||
|     Logger *logger  = (Logger *)malloc(sizeof(Logger)); | ||||
|  | ||||
|     logger->level   = level; | ||||
|     logger->level   = LOG_INFO; | ||||
|     logger->handler = loggingHandlerConsole(); | ||||
|     logger->name    = name; | ||||
|     logger->filter  = NULL; | ||||
|  | ||||
|     map_put(LOGGER_MAP, name, &logger); | ||||
|  | ||||
|     return logger; | ||||
| } | ||||
|  | ||||
| @@ -258,7 +276,17 @@ void destroyLogger(Logger *logger) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| __destroyLoggerForeach(const char *key, void *value, void *user_data) { | ||||
|     (void)user_data; | ||||
|     (void)key; | ||||
|     destroyLogger(*(Logger **)value); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 销毁日志对象 | ||||
|  */ | ||||
| void destroyDefaultLogger(void) { destroyLogger(ROOT_LOGGER); } | ||||
| void destroyDefaultLogger(void) { | ||||
|     map_foreach(LOGGER_MAP, __destroyLoggerForeach, NULL); | ||||
|     map_destroy(LOGGER_MAP); | ||||
| } | ||||
| @@ -15,9 +15,8 @@ static uint32_t hash_bytes(const void *data, size_t len) { | ||||
| } | ||||
|  | ||||
| /* 创建空 map */ | ||||
| Map *map_create(size_t key_len, size_t value_len) { | ||||
| Map *map_create(size_t value_len) { | ||||
|     Map *m        = calloc(1, sizeof(*m)); | ||||
|     m->key_len    = key_len; | ||||
|     m->value_len  = value_len; | ||||
|     m->bucket_cap = 8; /* 初始桶数 */ | ||||
|     m->bucket     = calloc(m->bucket_cap, sizeof(Node *)); | ||||
| @@ -25,15 +24,16 @@ Map *map_create(size_t key_len, size_t value_len) { | ||||
| } | ||||
|  | ||||
| /* 根据 key 找到桶下标 */ | ||||
| static size_t bucket_index(Map *m, const void *key) { | ||||
|     uint32_t h = hash_bytes(key, m->key_len); | ||||
| static size_t bucket_index(Map *m, const char *key) { | ||||
|     size_t   len = strlen(key); | ||||
|     uint32_t h   = hash_bytes(key, len); | ||||
|     return h & (m->bucket_cap - 1); /* 要求 bucket_cap 是 2 的幂 */ | ||||
| } | ||||
|  | ||||
| /* 在桶链中线性查找 */ | ||||
| static Node *find_in_chain(Node *head, const void *key, size_t key_len) { | ||||
| static Node *find_in_chain(Node *head, const char *key) { | ||||
|     for (; head; head = head->next) { | ||||
|         if (memcmp(head->kv, key, key_len) == 0) { | ||||
|         if (strcmp(head->key, key) == 0) { | ||||
|             return head; | ||||
|         } | ||||
|     } | ||||
| @@ -48,8 +48,9 @@ static void map_resize(Map *m) { | ||||
|     for (size_t i = 0; i < m->bucket_cap; ++i) { | ||||
|         Node *node = m->bucket[i]; | ||||
|         while (node) { | ||||
|             Node  *next     = node->next; | ||||
|             size_t idx      = hash_bytes(node->kv, m->key_len) & (new_cap - 1); | ||||
|             Node  *next = node->next; | ||||
|             size_t idx = | ||||
|                 hash_bytes(node->key, strlen(node->key)) & (new_cap - 1); | ||||
|             node->next      = new_bucket[idx]; | ||||
|             new_bucket[idx] = node; | ||||
|             node            = next; | ||||
| @@ -61,45 +62,47 @@ static void map_resize(Map *m) { | ||||
| } | ||||
|  | ||||
| /* 插入或覆盖 */ | ||||
| void map_put(Map *m, const void *key, const void *value) { | ||||
| void map_put(Map *m, const char *key, const void *value) { | ||||
|     if (m->size * 4 >= m->bucket_cap * 3) { /* 装载因子 0.75 */ | ||||
|         map_resize(m); | ||||
|     } | ||||
|  | ||||
|     size_t idx  = bucket_index(m, key); | ||||
|     Node  *node = find_in_chain(m->bucket[idx], key, m->key_len); | ||||
|     Node  *node = find_in_chain(m->bucket[idx], key); | ||||
|  | ||||
|     if (node) { /* 覆盖旧值 */ | ||||
|         memcpy(node->kv + m->key_len, value, m->value_len); | ||||
|         memcpy(node->value, value, m->value_len); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* 新建节点 */ | ||||
|     node       = malloc(sizeof(*node)); | ||||
|     node->kv   = malloc(m->key_len + m->value_len); | ||||
|     node->next = m->bucket[idx]; | ||||
|     memcpy(node->kv, key, m->key_len); | ||||
|     memcpy(node->kv + m->key_len, value, m->value_len); | ||||
|     node        = malloc(sizeof(*node)); | ||||
|     node->value = malloc(m->value_len); | ||||
|     node->next  = m->bucket[idx]; | ||||
|     node->key   = malloc(strlen(key) + 1); | ||||
|     memcpy(node->key, key, strlen(key) + 1); | ||||
|     memcpy(node->value, value, m->value_len); | ||||
|     m->bucket[idx] = node; | ||||
|     ++m->size; | ||||
| } | ||||
|  | ||||
| /* 查找 */ | ||||
| void *map_get(Map *m, const void *key) { | ||||
| void *map_get(Map *m, const char *key) { | ||||
|     size_t idx  = bucket_index(m, key); | ||||
|     Node  *node = find_in_chain(m->bucket[idx], key, m->key_len); | ||||
|     return node ? (node->kv + m->key_len) : NULL; | ||||
|     Node  *node = find_in_chain(m->bucket[idx], key); | ||||
|     return node ? node->value : NULL; | ||||
| } | ||||
|  | ||||
| /* 删除 */ | ||||
| bool map_erase(Map *m, const void *key) { | ||||
| bool map_erase(Map *m, const char *key) { | ||||
|     size_t idx  = bucket_index(m, key); | ||||
|     Node **link = &m->bucket[idx]; | ||||
|     for (; *link; link = &(*link)->next) { | ||||
|         if (memcmp((*link)->kv, key, m->key_len) == 0) { | ||||
|         if (strcmp((*link)->key, key) == 0) { | ||||
|             Node *to_del = *link; | ||||
|             *link        = to_del->next; | ||||
|             free(to_del->kv); | ||||
|             free(to_del->key); | ||||
|             free(to_del->value); | ||||
|             free(to_del); | ||||
|             --m->size; | ||||
|             return true; | ||||
| @@ -114,7 +117,8 @@ void map_destroy(Map *m) { | ||||
|         Node *node = m->bucket[i]; | ||||
|         while (node) { | ||||
|             Node *next = node->next; | ||||
|             free(node->kv); | ||||
|             free(node->key); | ||||
|             free(node->value); | ||||
|             free(node); | ||||
|             node = next; | ||||
|         } | ||||
| @@ -122,3 +126,18 @@ void map_destroy(Map *m) { | ||||
|     free(m->bucket); | ||||
|     free(m); | ||||
| } | ||||
|  | ||||
| /* 遍历 */ | ||||
| void map_foreach(Map *m, | ||||
|                  void (*callback)(const char *key, | ||||
|                                   void       *value, | ||||
|                                   void       *user_data), | ||||
|                  void *user_data) { | ||||
|     for (size_t i = 0; i < m->bucket_cap; ++i) { | ||||
|         Node *node = m->bucket[i]; | ||||
|         while (node) { | ||||
|             callback(node->key, node->value, user_data); | ||||
|             node = node->next; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -7,11 +7,12 @@ | ||||
|  | ||||
| typedef struct Node { | ||||
|     struct Node *next; | ||||
|     uint8_t     *kv; /* key 在前 value 在后 */ | ||||
|     char        *key; | ||||
|     void        *value; | ||||
| } Node; | ||||
|  | ||||
| struct Map { | ||||
|     size_t key_len, value_len; | ||||
|     size_t value_len; | ||||
|     size_t bucket_cap; | ||||
|     size_t size;   /* 当前元素个数 */ | ||||
|     Node **bucket; /* 指针数组 */ | ||||
| @@ -20,16 +21,23 @@ struct Map { | ||||
| typedef struct Map Map; | ||||
|  | ||||
| /* 创建空 map:key_len/value_len 以字节为单位 */ | ||||
| Map *map_create(size_t key_len, size_t value_len); | ||||
| Map *map_create(size_t value_len); | ||||
|  | ||||
| /* 插入或覆盖:<key> 必须指向 key_len 字节;同理 value */ | ||||
| void map_put(Map *m, const void *key, const void *value); | ||||
| void map_put(Map *m, const char *key, const void *value); | ||||
|  | ||||
| /* 查找:找到返回 value 指针;未找到返回 NULL */ | ||||
| void *map_get(Map *m, const void *key); | ||||
| void *map_get(Map *m, const char *key); | ||||
|  | ||||
| /* 删除:返回 true 表示确实删掉了 */ | ||||
| bool map_erase(Map *m, const void *key); | ||||
| bool map_erase(Map *m, const char *key); | ||||
|  | ||||
| /* 遍历: 遍历所有元素*/ | ||||
| void map_foreach(Map *m, | ||||
|                  void (*callback)(const char *key, | ||||
|                                   void       *value, | ||||
|                                   void       *user_data), | ||||
|                  void *user_data); | ||||
|  | ||||
| /* 销毁并释放所有内存 */ | ||||
| void map_destroy(Map *m); | ||||
|   | ||||
| @@ -20,6 +20,10 @@ add_executable(${PROJECT_NAME}filter test-filter.c) | ||||
| target_link_libraries(${PROJECT_NAME}filter logging) | ||||
| add_test(test_filter ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}filter${CMAKE_EXECUTEABLE_SUFFIX}) | ||||
|  | ||||
| #测试多log多次获取 | ||||
| add_executable(${PROJECT_NAME}logs test-logs.c) | ||||
| target_link_libraries(${PROJECT_NAME}logs logging) | ||||
| add_test(test_logs ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}logs${CMAKE_EXECUTEABLE_SUFFIX}) | ||||
|  | ||||
| #测试工具map | ||||
| add_executable(${PROJECT_NAME}map test-map.c) | ||||
|   | ||||
							
								
								
									
										24
									
								
								tests/test-logs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tests/test-logs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| #include "logging.h" | ||||
| #include "logging/logging-core.h" | ||||
| #include <stdio.h> | ||||
|  | ||||
| int main() { | ||||
|     Logger *t1  = getLogger("Test1"); | ||||
|     t1->level   = LOG_ERROR; | ||||
|  | ||||
|     Logger *t2  = getLogger("Test2"); | ||||
|     t2->level   = LOG_DEBUG; | ||||
|  | ||||
|     Logger *t11 = getLogger("Test1"); | ||||
|  | ||||
|     if (t1 == t11) { | ||||
|         printf("t1 and t11 are the same\n"); | ||||
|         printf("t1 log level: %s", LOG_LEVEL_STR[t11->level]); | ||||
|     } else { | ||||
|         printf("t1 and t11 are different\n"); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| @@ -1,17 +1,37 @@ | ||||
| #include "utils/logging-map.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| void foreach_callback(const char *key, void *value, void *user_data) { | ||||
|     (void)user_data; | ||||
|     printf("foreach key: %s, value: %d\n", key, *(int *)value); | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) { | ||||
|     (void)argc; | ||||
|     (void)argv; | ||||
|  | ||||
|     Map *map           = map_create(0, sizeof(int)); | ||||
|     Map *map           = map_create(sizeof(int)); | ||||
|  | ||||
|     const char *keys[] = {"key1", "key2", "key3", "key4", "key5"}; | ||||
|     const char *keys[] = {"key1", "key22", "key33", "key44", "key55"}; | ||||
|  | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         printf("put key %s,value %d\n", keys[i], i); | ||||
|         map_put(map, keys[i], &i); | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         int *value = map_get(map, keys[i]); | ||||
|         printf("get value: %d\n", *value); | ||||
|         if (*value != i) { | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     map_foreach(map, foreach_callback, NULL); | ||||
|  | ||||
|     map_destroy(map); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user