diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index 45df5f5d5..ab8a7112e 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -1,9 +1,13 @@ menu "test app" menuconfig USER_TEST bool "Enable application test function " - default n + default y if USER_TEST + menuconfig USER_TEST_HASH + bool "Config test hash" + default y + menuconfig USER_TEST_ADC bool "Config test adc" default n diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index 1cf919846..898ff9d9f 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -25,6 +25,10 @@ endif ifeq ($(CONFIG_ADD_XIZI_FETURES),y) SRC_FILES := test_shell.c + ifeq ($(CONFIG_USER_TEST_HASH),y) + SRC_FILES += test_hash/test_hash.c + endif + ifeq ($(CONFIG_USER_TEST_ADC),y) SRC_FILES += test_adc.c endif diff --git a/APP_Framework/Applications/app_test/test_hash/README.md b/APP_Framework/Applications/app_test/test_hash/README.md new file mode 100644 index 000000000..7f26ffc67 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/README.md @@ -0,0 +1,301 @@ +# 热身赛一级赛题1:基于cortex-m3-emulator实现哈希表并测试验证 + +## 1. 简介 +本项目是基于cortex-m3-emulator实现哈希表并测试验证 +test_hash.h定义所需要的宏,结构体,函数声明 +test_hash.c用于实现哈希表的创建、删除、增删改查等具体操作,以及构建测试函数,并且注入到shell中 + +## 2. 数据结构设计说明 +- 通过数组和链表实现哈希表,链地址法解决哈希冲突,默认数组长度TABLE_SIZE,节点数据结构Entry,哈希表数据结构HashTable +```c +/* the size of hash table */ +#define TABLE_SIZE (1024) +/* element of the hash table's chain list */ +struct Entry +{ + char* key; + void* value; + struct Entry* next; + void (*FreeValue)(void*); +}; +/* HashTable */ +typedef struct +{ + struct Entry ** table; +}HashTable; +``` +- 定义哈希表的创建、删除、增删改查 +```c +/* new an instance of HashTable */ +HashTable* HashTableNew(); + +/* +delete an instance of HashTable, +all values are removed auotmatically. +*/ +void HashTableDelete(HashTable* ht); + +/* +add or update a value to ht, +free_value(if not NULL) is called automatically when the value is removed. +return 0 if success, -1 if error occurred. +*/ +int HashTablePut(HashTable* ht, char* key, void* value); +int HashTablePut2(HashTable* ht, char* key, void* value, void(*free_value)(void*)); + +/* get a value indexed by key, return NULL if not found. */ +void* HashTableGet(HashTable* ht, char* key); + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* ht, char* key); +``` +- 实现哈希表的创建、删除、增删改查 +```c +/* constructor of struct Entry */ +static void InitEntry(struct Entry* entry) +{ + entry->key = NULL; + entry->value = NULL; + entry->next = NULL; + entry->FreeValue = NULL; +} + +/* destructor of struct Entry */ +static void FreeEntry(struct Entry* entry) +{ + if (entry){ + if (entry->FreeValue){ + entry->FreeValue(entry->value); + } + free(entry->key); + entry->key = NULL; + free(entry); + } +} + +/* the classic Times33 hash function */ +static unsigned int Hash33(char* key) +{ + unsigned int hash = 0; + while (*key){ + hash = (hash << 5) + hash + *key++; + } + return hash; +} + +/* new a HashTable instance */ +HashTable* HashTableNew() +{ + HashTable* hash_table = malloc(sizeof(HashTable)); + + if (NULL == hash_table){ + HashTableDelete(hash_table); + return NULL; + } + hash_table->table = malloc(sizeof(struct Entry*) * TABLE_SIZE); + if (NULL == hash_table->table){ + HashTableDelete(hash_table); + return NULL; + } + memset(hash_table->table, 0, sizeof(struct Entry*) * TABLE_SIZE); + + return hash_table; +} + +/* delete a HashTable instance */ +void HashTableDelete(HashTable* hash_table) +{ + if (hash_table){ + if (hash_table->table){ + int i = 0; + for (i = 0; i < TABLE_SIZE; i++){ + struct Entry* p = hash_table->table[i]; + struct Entry* q = NULL; + while (p){ + q = p->next; + FreeEntry(p); + p = q; + } + } + free(hash_table->table); + hash_table->table = NULL; + } + free(hash_table); + } +} + +/* insert or update a value indexed by key without FreeValue */ +int HashTablePut(HashTable* hash_table, char* key, void* value) +{ + return HashTablePut2(hash_table,key,value,NULL); +} + +/* insert or update a value indexed by key with FreeValue */ +int HashTablePut2(HashTable* hash_table, char* key, void* value, void(*FreeValue)(void*)) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + char* key_str = malloc(strlen(key) + 1); + if (key_str == NULL){ + return -1; + } + char* value_str = malloc(strlen(value) + 1); + if (value_str == NULL){ + return -1; + } + strcpy(key_str, key); + strcpy(value_str,value); + + while (p){ /* if key is already stroed, update its value */ + if (strcmp(p->key, key) == 0){ + if (p->FreeValue) { + p->FreeValue(p->value); + } + p->value = value_str; + p->FreeValue = FreeValue; + break; + } + prep = p; + p = p->next; + } + + if (p == NULL){ /* if key has not been stored, then add it */ + struct Entry * entry = malloc(sizeof(struct Entry)); + if (NULL == entry){ + free(key_str); + key_str = NULL; + free(value_str); + value_str = NULL; + return -1; + } + InitEntry(entry); + entry->next = NULL; + entry->key = key_str; + entry->value = value_str; + entry->FreeValue = FreeValue; + + if (prep == NULL){ + hash_table->table[i] = entry; + } + else{ + prep->next = entry; + } + } + return 0; +} + +/* get a value indexed by key */ +void* HashTableGet(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + while (p){ + if (strcmp(key, p->key) == 0){ + return p->value; + } + p = p->next; + } + return NULL; +} + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + while (p){ + if (strcmp(key, p->key) == 0) { + FreeEntry(p); + if (p == prep) { + hash_table->table[i] = NULL; + } + else { + prep->next = p->next; + } + } + prep = p; + p = p->next; + } +} +``` +## 3. 测试程序说明 +- 测试哈希表的基本操作 +```c +/* the test order menu */ +void ShowMenu() +{ + printf("================order menu================\n"); + printf("==========0:insert(TestHash 0 x 2)========\n"); + printf("==========1:get(TestHash 1 x)=============\n"); + printf("==========2:update(TestHash 2 x 1)========\n"); + printf("==========3:remove(TestHash 3 x)==========\n"); +} + +HashTable* hash_table = NULL; +/* test for hash table*/ +void TestHash(int argc, char* argv[]) +{ + if (argc == 1){ + printf("please use TestHash help to check orders\n"); + return; + } + if (strcmp(argv[1],"help") == 0) ShowMenu(); + + if (strcmp(argv[1],"0") == 0){ // insert + if(hash_table == NULL){ + hash_table = HashTableNew(); + } + HashTablePut(hash_table,argv[2],argv[3]); + char* value = (char*)HashTableGet(hash_table,argv[2]); + printf("insert key=%s,val=%s; sucessful!\n",argv[2],value); + }else if (strcmp(argv[1],"1") == 0){ // get + if(hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s)\n",argv[2]); + }else{ + printf("get key=%s,value=%s; answer=%s\n",argv[2],value,value); + } + }else if (strcmp(argv[1],"2") == 0){ // update + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s). please insert first.\n",argv[2]); + }else{ + HashTablePut(hash_table,argv[2],argv[3]); + printf("update key=%s,old_value=%s,value=%s; sucessful\n",argv[2],value,argv[3]); + } + }else if (strcmp(argv[1],"3") == 0){ // remove + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + HashTableRemove(hash_table,argv[2]); + printf("remove key=%s; sucessful!\n",argv[2]); + } + return; +} +PRIV_SHELL_CMD_FUNCTION(TestHash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR); +``` + +## 4. 运行结果(##需结合运行测试截图按步骤说明##) +1. 输入help查看letter shell可以调用的命令 +2. 输入TestHash命令,提示用TestHash help查看TestHash的命令 +3. 没有插入元素就查看元素:TestHash 1 x --> 哈希表为空,提示先插入 +4. 没有插入就删除元素:TestHash 3 x --> 哈希表为空,提示先插入 +5. 插入x=2: TestHash 0 x 2 +6. 查找x: TestHash 1 x +7. 更新x=100: TestHash 2 x 100 +8. 查找更新后的x: TestHash 1 x +9. 删除x: TestHash 3 x +10. 确认是否被删除: TestHash 1 x +![](./test.png) \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_hash/test.png b/APP_Framework/Applications/app_test/test_hash/test.png new file mode 100644 index 000000000..d80362773 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_hash/test.png differ diff --git a/APP_Framework/Applications/app_test/test_hash/test_hash.c b/APP_Framework/Applications/app_test/test_hash/test_hash.c new file mode 100644 index 000000000..fa682a7e2 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/test_hash.c @@ -0,0 +1,260 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: test_hash.c +* @brief: a application of hash table +* @version: 1.0 +* @author: bdislab_final +* @date: 2023/6/17 +*/ + +#include "test_hash.h" +#include +#include +#include +#include + +#ifdef ADD_XIZI_FETURES + +/* constructor of struct Entry */ +static void InitEntry(struct Entry* entry) +{ + entry->key = NULL; + entry->value = NULL; + entry->next = NULL; + entry->FreeValue = NULL; +} + +/* destructor of struct Entry */ +static void FreeEntry(struct Entry* entry) +{ + if (entry){ + if (entry->FreeValue){ + entry->FreeValue(entry->value); + } + free(entry->key); + entry->key = NULL; + free(entry); + } +} + +/* the classic Times33 hash function */ +static unsigned int Hash33(char* key) +{ + unsigned int hash = 0; + while (*key){ + hash = (hash << 5) + hash + *key++; + } + return hash; +} + +/* new a HashTable instance */ +HashTable* HashTableNew() +{ + HashTable* hash_table = malloc(sizeof(HashTable)); + + if (NULL == hash_table){ + HashTableDelete(hash_table); + return NULL; + } + hash_table->table = malloc(sizeof(struct Entry*) * TABLE_SIZE); + if (NULL == hash_table->table){ + HashTableDelete(hash_table); + return NULL; + } + memset(hash_table->table, 0, sizeof(struct Entry*) * TABLE_SIZE); + + return hash_table; +} + +/* delete a HashTable instance */ +void HashTableDelete(HashTable* hash_table) +{ + if (hash_table){ + if (hash_table->table){ + int i = 0; + for (i = 0; i < TABLE_SIZE; i++){ + struct Entry* p = hash_table->table[i]; + struct Entry* q = NULL; + while (p){ + q = p->next; + FreeEntry(p); + p = q; + } + } + free(hash_table->table); + hash_table->table = NULL; + } + free(hash_table); + } +} + +/* insert or update a value indexed by key without FreeValue */ +int HashTablePut(HashTable* hash_table, char* key, void* value) +{ + return HashTablePut2(hash_table,key,value,NULL); +} + +/* insert or update a value indexed by key with FreeValue */ +int HashTablePut2(HashTable* hash_table, char* key, void* value, void(*FreeValue)(void*)) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + char* key_str = malloc(strlen(key) + 1); + if (key_str == NULL){ + return -1; + } + char* value_str = malloc(strlen(value) + 1); + if (value_str == NULL){ + return -1; + } + strcpy(key_str, key); + strcpy(value_str,value); + + while (p){ /* if key is already stroed, update its value */ + if (strcmp(p->key, key) == 0){ + if (p->FreeValue) { + p->FreeValue(p->value); + } + p->value = value_str; + p->FreeValue = FreeValue; + break; + } + prep = p; + p = p->next; + } + + if (p == NULL){ /* if key has not been stored, then add it */ + struct Entry * entry = malloc(sizeof(struct Entry)); + if (NULL == entry){ + free(key_str); + key_str = NULL; + free(value_str); + value_str = NULL; + return -1; + } + InitEntry(entry); + entry->next = NULL; + entry->key = key_str; + entry->value = value_str; + entry->FreeValue = FreeValue; + + if (prep == NULL){ + hash_table->table[i] = entry; + } + else{ + prep->next = entry; + } + } + return 0; +} + +/* get a value indexed by key */ +void* HashTableGet(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + struct Entry* p = hash_table->table[i]; + while (p){ + if (strcmp(key, p->key) == 0){ + return p->value; + } + p = p->next; + } + return NULL; +} + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* hash_table, char* key) +{ + int i = Hash33(key) % TABLE_SIZE; + + struct Entry* p = hash_table->table[i]; + struct Entry* prep = p; + while (p){ + if (strcmp(key, p->key) == 0) { + FreeEntry(p); + if (p == prep) { + hash_table->table[i] = NULL; + } + else { + prep->next = p->next; + } + } + prep = p; + p = p->next; + } +} + +/* the test order menu */ +void ShowMenu() +{ + printf("================order menu================\n"); + printf("==========0:insert(TestHash 0 x 2)========\n"); + printf("==========1:get(TestHash 1 x)=============\n"); + printf("==========2:update(TestHash 2 x 1)========\n"); + printf("==========3:remove(TestHash 3 x)==========\n"); +} + +HashTable* hash_table = NULL; +/* test for hash table*/ +void TestHash(int argc, char* argv[]) +{ + if (argc == 1){ + printf("please use TestHash help to check orders\n"); + return; + } + if (strcmp(argv[1],"help") == 0) ShowMenu(); + + if (strcmp(argv[1],"0") == 0){ // insert + if(hash_table == NULL){ + hash_table = HashTableNew(); + } + HashTablePut(hash_table,argv[2],argv[3]); + char* value = (char*)HashTableGet(hash_table,argv[2]); + printf("insert key=%s,val=%s; sucessful!\n",argv[2],value); + }else if (strcmp(argv[1],"1") == 0){ // get + if(hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s)\n",argv[2]); + }else{ + printf("get key=%s,value=%s; answer=%s\n",argv[2],value,value); + } + }else if (strcmp(argv[1],"2") == 0){ // update + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + char* value = (char*)HashTableGet(hash_table,argv[2]); + if (value == NULL){ + printf("without such key(%s). please insert first.\n",argv[2]); + }else{ + HashTablePut(hash_table,argv[2],argv[3]); + printf("update key=%s,old_value=%s,value=%s; sucessful\n",argv[2],value,argv[3]); + } + }else if (strcmp(argv[1],"3") == 0){ // remove + if (hash_table == NULL){ + printf("error: hash table is NULL. please insert first.\n"); + return; + } + HashTableRemove(hash_table,argv[2]); + printf("remove key=%s; sucessful!\n",argv[2]); + } + return; +} +PRIV_SHELL_CMD_FUNCTION(TestHash, a hash test sample, PRIV_SHELL_CMD_MAIN_ATTR); +#endif \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_hash/test_hash.h b/APP_Framework/Applications/app_test/test_hash/test_hash.h new file mode 100644 index 000000000..2dd3eace4 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hash/test_hash.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** + * @file test_hash.h + * @brief a application of hash table + * @version 1.0 + * @author bdislab_final + * @date 2023/6/17 + */ + +#ifndef TEST_HASH_H +#define TEST_HASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* the size of hash table */ +#define TABLE_SIZE (1024) + +/* element of the hash table's chain list */ +struct Entry +{ + char* key; + void* value; + struct Entry* next; + void (*FreeValue)(void*); +}; + +/* HashTable */ +typedef struct +{ + struct Entry ** table; +}HashTable; + + +/* new an instance of HashTable */ +HashTable* HashTableNew(); + +/* +delete an instance of HashTable, +all values are removed auotmatically. +*/ +void HashTableDelete(HashTable* ht); + +/* +add or update a value to ht, +free_value(if not NULL) is called automatically when the value is removed. +return 0 if success, -1 if error occurred. +*/ +int HashTablePut(HashTable* ht, char* key, void* value); +int HashTablePut2(HashTable* ht, char* key, void* value, void(*free_value)(void*)); + +/* get a value indexed by key, return NULL if not found. */ +void* HashTableGet(HashTable* ht, char* key); + +/* remove a value indexed by key */ +void HashTableRemove(HashTable* ht, char* key); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 000000000..95221430e --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cd /home/yanglong/Desktop/xiuos/xiuos/Ubiquitous/XiZi_IIoT +make BOARD=cortex-m3-emulator distclean +make BOARD=cortex-m3-emulator menuconfig +make BOARD=cortex-m3-emulator +sleep +qemu-system-arm -machine lm3s6965evb -nographic -kernel build/XiZi-cortex-m3-emulator.elf \ No newline at end of file