Browse Source

first version

smartmx 3 năm trước cách đây
commit
41a5e5acf1
9 tập tin đã thay đổi với 948 bổ sung0 xóa
  1. 201 0
      LICENSE
  2. 17 0
      SConscript
  3. 4 0
      _config.yml
  4. 99 0
      examples/hash_match_demo.c
  5. 142 0
      hash-match.c
  6. 169 0
      hash-match.h
  7. 73 0
      murmurhash3.c
  8. 36 0
      murmurhash3.h
  9. 207 0
      readme.md

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 17 - 0
SConscript

@@ -0,0 +1,17 @@
+from building import *
+import rtconfig
+
+cwd = GetCurrentDir()
+
+# init src
+src = []
+src += Glob('*.c')
+
+if GetDepend(['PKG_USING_HASH_MATCH_DEMO']):
+    src += Glob("examples/hash_match_demo.c")
+
+CPPPATH = [cwd]
+
+group = DefineGroup('hash-match', src, depend = ['PKG_USING_HASH_MATCH'], CPPPATH = CPPPATH)
+
+Return('group')

+ 4 - 0
_config.yml

@@ -0,0 +1,4 @@
+title:  hash-match
+description: Using Hashmap algorithm on MCUs.
+show_downloads: true
+theme: jekyll-theme-cayman

+ 99 - 0
examples/hash_match_demo.c

@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022, smartmx <smartmx@qq.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-04-03     smartmx      the first version
+ *
+ */
+#include "hash-match.h"
+#include <rtthread.h>
+
+/* test1 */
+void hash_match_test1func(void *t)
+{
+    rt_kprintf("test1\n");
+}
+const uint8_t hash_match_test1key[] = {251, 35, 0, 189, 76, 32, 232, 16, 168, 192};
+HASH_MATCH_EXPORT(hash_match_test, hash_match_test1, hash_match_test1key, sizeof(hash_match_test1key), hash_match_test1func, "this is test 1");
+
+/* different section group with same key, for test. */
+void hash_match_test1func1(void *t)
+{
+    rt_kprintf("test11\n");
+}
+HASH_MATCH_EXPORT(hash_match_test1, hash_match_test11, hash_match_test1key, sizeof(hash_match_test1key), hash_match_test1func1, "this is test 11");
+
+/* test2 */
+void hash_match_test2func(void *t)
+{
+    rt_kprintf("test2\n");
+}
+const uint8_t hash_match_test2key[] = {51, 135, 10, 0, 33, 67, 45, 123, 172, 8, 0};
+HASH_MATCH_EXPORT(hash_match_test, hash_match_test2, hash_match_test2key, sizeof(hash_match_test2key), hash_match_test2func, "this is test 2");
+
+/* different section group with same key, for test. */
+void hash_match_test2func1(void *t)
+{
+    rt_kprintf("test21\n");
+}
+HASH_MATCH_EXPORT(hash_match_test1, hash_match_test21, hash_match_test2key, sizeof(hash_match_test2key), hash_match_test2func1, "this is test 21");
+
+/* test3 */
+void hash_match_test3func(void *t)
+{
+    rt_kprintf("test3\n");
+}
+const uint8_t hash_match_test3key[] = {8, 99, 23, 170, 234, 7, 212, 65, 20, 88, 19, 122};
+HASH_MATCH_EXPORT(hash_match_test, hash_match_test3, hash_match_test3key, sizeof(hash_match_test3key), hash_match_test3func, "this is test 3");
+
+/* different section group with same key, for test. */
+void hash_match_test3func1(void *t)
+{
+    rt_kprintf("test31\n");
+}
+HASH_MATCH_EXPORT(hash_match_test1, hash_match_test31, hash_match_test3key, sizeof(hash_match_test3key), hash_match_test3func1, "this is test 31");
+
+static void hash_match_test_task(void *arg)
+{
+    /* init hash_match_test section group. */
+    HASH_MATCH_INIT(hash_match_test);
+    HASH_MATCH_LIST(hash_match_test);
+
+    /* init hash_match_test1 section group. */
+    HASH_MATCH_INIT(hash_match_test1);
+    HASH_MATCH_LIST(hash_match_test1);
+    while (1)
+    {
+        HASH_MATCH(hash_match_test, hash_match_test1key, sizeof(hash_match_test1key), NULL);
+        HASH_MATCH(hash_match_test, hash_match_test2key, sizeof(hash_match_test2key), NULL);
+        HASH_MATCH(hash_match_test, hash_match_test3key, sizeof(hash_match_test3key), NULL);
+        /* mix up the length, to try. */
+        HASH_MATCH(hash_match_test, hash_match_test1key, sizeof(hash_match_test2key), NULL);
+        HASH_MATCH(hash_match_test, hash_match_test2key, sizeof(hash_match_test3key), NULL);
+        HASH_MATCH(hash_match_test, hash_match_test3key, sizeof(hash_match_test1key), NULL);
+        /* try with different section group. */
+        HASH_MATCH(hash_match_test1, hash_match_test1key, sizeof(hash_match_test1key), NULL);
+        HASH_MATCH(hash_match_test1, hash_match_test2key, sizeof(hash_match_test2key), NULL);
+        HASH_MATCH(hash_match_test1, hash_match_test3key, sizeof(hash_match_test3key), NULL);
+        rt_thread_mdelay(1000);
+    }
+}
+
+int hash_match_test_main(void)
+{
+    rt_thread_t tid = RT_NULL;
+
+    /* Create background ticks thread */
+    tid = rt_thread_create("hash-match", hash_match_test_task, RT_NULL, 1024, 10, 10);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+
+INIT_APP_EXPORT(hash_match_test_main);

+ 142 - 0
hash-match.c

@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2022, smartmx <smartmx@qq.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-04-03     smartmx      the first version
+ *
+ */
+#include "hash-match.h"
+
+/**
+ * check all calculated hash code in the group, compare with hash_code.
+ *
+ * @param start the hash match group start address.
+ * @param end the hash match group end address.
+ * @param hash_code the hash code which is need be checked.
+ *
+ * @return None.
+ */
+void hash_match_check(const hash_match_t *start, const hash_match_t *end, uint32_t hash_code)
+{
+    const hash_match_t *check_start = (const hash_match_t *)start;
+    HASH_MATCH_PRINTF("check hash_code:'%08x'\n", hash_code);
+    while (1)
+    {
+        if (end <= check_start)
+        {
+            break;
+        }
+        if (*(check_start->hash_code) == hash_code)
+        {
+            HASH_MATCH_PRINTF("hash match check error, hash_code %08x is duplicated!\n", (uint32_t)check_start);
+            break;
+        }
+        check_start++;
+    }
+}
+
+/**
+ * init a hash code group.
+ *
+ * @param start the hash match group start address.
+ * @param end the hash match group end address.
+ *
+ * @return None.
+ */
+void hash_match_group_init(const hash_match_t *start, const hash_match_t *end)
+{
+    const hash_match_t *init_start = (const hash_match_t *)start;
+    while (1)
+    {
+        if (end <= init_start)
+        {
+            break;
+        }
+        *(init_start->hash_code) = hash_match_caculate(init_start->hash_key_src, init_start->hash_key_len);
+#if HASH_MATCH_INIT_CHECK
+        hash_match_check(start, init_start, *(init_start->hash_code));
+#endif
+        init_start++;
+    }
+
+}
+
+/**
+ * check all calculated hash code in the group, compare with hash_code.
+ *
+ * @param start the hash match group start address.
+ * @param end the hash match group end address.
+ * @param src the hash key source pointer.
+ * @param len the length of hash key source.
+ * @param (void*) parameter when calling handler.
+ *
+ * @return None.
+ */
+void hash_match_group(const hash_match_t *start, const hash_match_t *end, const void *src, uint32_t len, void *param)
+{
+    const hash_match_t *find_start = (const hash_match_t *)start;
+    uint32_t hash_code;
+    hash_code = hash_match_caculate(src, len);
+    while (1)
+    {
+        if (end <= find_start)
+        {
+            break;
+        }
+        if ((*(find_start->hash_code) == hash_code) && (len == find_start->hash_key_len))
+        {
+#if HASH_MATCH_COMPARE_KEY
+            if (hash_match_memcmp(src, find_start->hash_key_src, len) == HASH_MATCH_MEMCMP_SAME)
+            {
+#endif
+                if (find_start->handler != NULL)
+                {
+                    find_start->handler(param);
+                }
+                break;
+#if HASH_MATCH_COMPARE_KEY
+            }
+#endif
+        }
+        find_start++;
+    }
+}
+
+/**
+ * list all hash key info in a hash code group.
+ *
+ * @param start the hash match group start address.
+ * @param end the hash match group end address.
+ *
+ * @return None.
+ */
+void hash_match_group_list(const hash_match_t *start, const hash_match_t *end)
+{
+    const hash_match_t *list_start = (const hash_match_t *)start;
+    uint32_t len;
+    while (1)
+    {
+        if (end <= list_start)
+        {
+            break;
+        }
+        len = 0;
+        HASH_MATCH_PRINTF("hash match key:%02x", list_start->hash_key_src[len]);
+        len++;
+        while (len < list_start->hash_key_len)
+        {
+            HASH_MATCH_PRINTF(" %02x", list_start->hash_key_src[len]);
+            len++;
+        }
+        HASH_MATCH_PRINTF("\nhash match key len:%d\n", list_start->hash_key_len);
+        HASH_MATCH_PRINTF("hash match hash code:%08x\n", *(list_start->hash_code));
+#if HASH_MATCH_SAVE_DESC
+        HASH_MATCH_PRINTF("hash match description: %s\n", list_start->hash_desc);
+#endif
+        list_start++;
+    }
+}
+

+ 169 - 0
hash-match.h

@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2022, smartmx <smartmx@qq.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-04-03     smartmx      the first version
+ *
+ */
+#ifndef _HASH_MACTH_H_
+#define _HASH_MACTH_H_
+
+#include "stdio.h"
+#include "stdint.h"
+#include "murmurhash3.h"
+
+/*
+ * @Note: hash-match use murmur3 hash algorithm in default: https://github.com/aappleby/smhasher.
+ *        you can use your own hash algorithm by change the definition "hash_match_caculate".
+ */
+#define hash_match_caculate         murmurhash3_caculate32
+
+/* whether save description of hash source or not, set 0 will not save description. */
+#define HASH_MATCH_SAVE_DESC        0
+
+/* set HASH_MATCH_INIT_CHECK to 1 will check all hash values in one group during init a group, report if some hash value is duplicated. */
+#define HASH_MATCH_INIT_CHECK       0
+
+/* change to your own printf function, or don't use it. */
+#define HASH_MATCH_PRINTF           printf
+
+/* whether compare key when hash_code is same. */
+#define HASH_MATCH_COMPARE_KEY      1
+
+/* use string.h or self functions to compare key. */
+#define HASH_MATCH_USE_STRING_H     1
+
+#if HASH_MATCH_USE_STRING_H
+    #include "string.h"
+    #define hash_match_memcmp       memcmp
+    #define HASH_MATCH_MEMCMP_SAME  0
+#else
+    #define hash_match_memcmp
+    #define HASH_MATCH_MEMCMP_SAME
+#endif
+
+typedef void (*hash_match_handler)(void *);
+
+typedef struct _hash_match_struct
+{
+    const uint8_t       *hash_key_src;
+    uint32_t            hash_key_len;
+    uint32_t            *hash_code;
+    hash_match_handler  handler;
+#if HASH_MATCH_SAVE_DESC
+    const char          *hash_desc;
+#endif
+} hash_match_t;
+
+#if HASH_MATCH_SAVE_DESC
+#define HASH_MATCH_EXPORT(GROUP, NAME, hash_key_src, hash_key_len, handler, hash_desc)      \
+    static const char NAME##_hash_desc[] = hash_desc;                                       \
+    static uint32_t NAME##_hash_code = 0;                                                   \
+    HASH_MATCH_USED const hash_match_t NAME HASH_MATCH_SECTION(#GROUP)=                     \
+    {                                                                                       \
+        hash_key_src,                                                                       \
+        hash_key_len,                                                                       \
+        &NAME##_hash_code,                                                                  \
+        &handler,                                                                           \
+        NAME##_hash_desc,                                                                   \
+    }
+#else
+/* use va_args to adapt from codes which has HASH_MATCH_SAVE_DESC enabled. */
+#define HASH_MATCH_EXPORT(GROUP, NAME, hash_key_src, hash_key_len, handler, ...)            \
+    static uint32_t NAME##_hash_code = 0;                                                   \
+    HASH_MATCH_USED const hash_match_t NAME HASH_MATCH_SECTION(#GROUP)=                     \
+    {                                                                                       \
+        hash_key_src,                                                                       \
+        hash_key_len,                                                                       \
+        &NAME##_hash_code,                                                                  \
+        &handler,                                                                           \
+    }
+#endif
+
+/* we do not use these functions directly, but use macro definitions functions instead. */
+extern void hash_match_group_init(const hash_match_t *start, const hash_match_t *end);
+
+extern void hash_match_group(const hash_match_t *start, const hash_match_t *end, const void *src, uint32_t len, void *param);
+
+extern void hash_match_group_list(const hash_match_t *start, const hash_match_t *end);
+
+/* Compiler Related Definitions */
+#if defined(__CC_ARM) || defined(__CLANG_ARM)           /* ARM Compiler */
+
+#define HASH_MATCH_SECTION(x)                   __attribute__((section(x)))
+#define HASH_MATCH_USED                         __attribute__((used))
+
+#define HASH_MATCH_INIT(GROUP)  do          \
+    {                                       \
+        extern const int GROUP##$$Base;     \
+        extern const int GROUP##$$Limit;    \
+        hash_match_group_init((const hash_match_t*)&GROUP##$$Base, (const hash_match_t*)&GROUP##$$Limit);   \
+    } while(0)
+
+#define HASH_MATCH(GROUP, SRC, LEN, PARAMS)    do       \
+    {                                                   \
+        extern const int GROUP##$$Base;                 \
+        extern const int GROUP##$$Limit;                \
+        hash_match_group((const hash_match_t*)&GROUP##$$Base, (const hash_match_t*)&GROUP##$$Limit, SRC, LEN, PARAMS); \
+    } while(0)
+
+#define HASH_MATCH_LIST(GROUP)  do          \
+    {                                       \
+        extern const int GROUP##$$Base;     \
+        extern const int GROUP##$$Limit;    \
+        hash_match_group_list((const hash_match_t*)&GROUP##$$Base, (const hash_match_t*)&GROUP##$$Limit);  \
+    } while(0)
+
+#elif defined (__IAR_SYSTEMS_ICC__)                     /* for IAR Compiler */
+
+#define HASH_MATCH_SECTION(x)                   @ x
+#define HASH_MATCH_USED                         __root
+
+#define HASH_MATCH_INIT(GROUP)  do  \
+    {                               \
+        hash_match_group_init((const hash_match_t*)(__section_begin(#GROUP)), (const hash_match_t*)(__section_end(#GROUP)));  \
+    } while(0)
+
+#define HASH_MATCH(GROUP, SRC, LEN, PARAMS)    do   \
+    {                                               \
+        hash_match_group((const hash_match_t*)(__section_begin(#GROUP)), (const hash_match_t*)(__section_end(#GROUP)), SRC, LEN, PARAMS); \
+    } while(0)
+
+#define HASH_MATCH_LIST(GROUP)  do              \
+    {                                           \
+        hash_match_group_list((const hash_match_t*)(__section_begin(#GROUP)), (const hash_match_t*)(__section_end(#GROUP)));  \
+    } while(0)
+
+#elif defined (__GNUC__)                                /* GNU GCC Compiler */
+
+#define HASH_MATCH_SECTION(x)                       __attribute__((section(x)))
+#define HASH_MATCH_USED                             __attribute__((used))
+
+#define HASH_MATCH_INIT(GROUP)  do      \
+    {                                   \
+        extern const int GROUP##_start; \
+        extern const int GROUP##_end;   \
+        hash_match_group_init((const hash_match_t*)&GROUP##_start, (const hash_match_t*)&GROUP##_end);  \
+    } while(0)
+
+#define HASH_MATCH(GROUP, SRC, LEN, PARAMS)    do   \
+    {                                               \
+        extern const int GROUP##_start;             \
+        extern const int GROUP##_end;               \
+        hash_match_group((const hash_match_t*)&GROUP##_start, (const hash_match_t*)&GROUP##_end, (uint8_t *)SRC, LEN, PARAMS);    \
+    } while(0)
+
+#define HASH_MATCH_LIST(GROUP)  do          \
+    {                                       \
+        extern const int GROUP##_start;     \
+        extern const int GROUP##_end;       \
+        hash_match_group_list((const hash_match_t*)&GROUP##_start, (const hash_match_t*)&GROUP##_end);  \
+    } while(0)
+#else
+#error not supported tool chain
+#endif
+
+#endif

+ 73 - 0
murmurhash3.c

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022, smartmx <smartmx@qq.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-04-03     smartmx      the first version
+ *
+ */
+/*
+ * @Note:
+ * This is murmur3 hash algorithm: https://github.com/aappleby/smhasher.
+ * But coded with c instead.
+ * This repository only accomplish 32bit hash algorithm.
+ */
+#include "murmurhash3.h"
+
+#define ROTL32(x,y) ((x << y) | (x >> (32 - y)))
+
+uint32_t murmurhash3_caculate32(const void *hash_key, uint32_t len)
+{
+    const uint8_t *hash_key_ptr = (const uint8_t *)hash_key;
+    int nblocks = len / 4;
+    uint32_t hash = MURMURHASH3_SEED_VALUE;
+    uint32_t data;
+
+    /* body */
+    while (nblocks > 0)
+    {
+        /* get 32bit data */
+        data = (hash_key_ptr[0] << 24) | (hash_key_ptr[1] << 16) | (hash_key_ptr[2] << 8) | (hash_key_ptr[3]);
+
+        data *= MURMURHASH3_C1_VALUE;
+        data = ROTL32(data, MURMURHASH3_R1_VALUE);
+        data *= MURMURHASH3_C2_VALUE;
+
+        hash ^= data;
+        hash = ROTL32(hash, MURMURHASH3_R2_VALUE);
+        hash = hash * MURMURHASH3_M_VALUE + MURMURHASH3_N_VALUE;
+
+        hash_key_ptr += 4;
+        nblocks--;
+    }
+    /* tail */
+    data = 0;
+    switch (len & 3)
+    {
+    case 3:
+        data ^= (hash_key_ptr[2] << 16);/* @suppress("No break at end of case") */
+    case 2:
+        data ^= (hash_key_ptr[1] << 8); /* @suppress("No break at end of case") */
+    case 1:
+        data ^= hash_key_ptr[0];
+        data *= MURMURHASH3_C1_VALUE;
+        data = ROTL32(data, MURMURHASH3_R1_VALUE);
+        data *= MURMURHASH3_C2_VALUE;
+        hash ^= data;
+    }
+
+    /* finalization */
+
+    hash ^= len;
+
+    /* Finalization mix - force all bits of a hash block to avalanche */
+    hash ^= hash >> 16;
+    hash *= 0x85ebca6b;
+    hash ^= hash >> 13;
+    hash *= 0xc2b2ae35;
+    hash ^= hash >> 16;
+
+    return hash;
+}

+ 36 - 0
murmurhash3.h

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, smartmx <smartmx@qq.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-04-03     smartmx      the first version
+ *
+ */
+/*
+ * @Note:
+ * This is murmur3 hash algorithm: https://github.com/aappleby/smhasher.
+ * But coded with c instead.
+ * This repository only accomplish 32bit hash algorithm.
+ */
+#ifndef _MURMURHASH3_H_
+#define _MURMURHASH3_H_
+
+#include "stdio.h"
+#include "stdint.h"
+
+/* The seed value, you can change as you want. */
+#define MURMURHASH3_SEED_VALUE       0x31313137
+
+/* The hash calculate parameters value, don't change it unless it's necessary. */
+#define MURMURHASH3_C1_VALUE         0xcc9e2d51
+#define MURMURHASH3_C2_VALUE         0x1b873593
+#define MURMURHASH3_R1_VALUE         15
+#define MURMURHASH3_R2_VALUE         13
+#define MURMURHASH3_M_VALUE          5
+#define MURMURHASH3_N_VALUE          0xe6546b64
+
+extern uint32_t murmurhash3_caculate32(const void *hash_key, uint32_t len);
+
+#endif /* _MURMURHASH3_H_ */

+ 207 - 0
readme.md

@@ -0,0 +1,207 @@
+# hash-match
+
+哈希匹配算法在单片机上的应用
+
+## hash-match设计前言
+
+在单片机日常开发中,总会遇到根据收到的不同数据执行不同的程序,通常都会使用`memcmp`或者`strcmp`进行比较。
+
+在匹配数据情况不多时,的确很合适。
+
+但是一旦工程量变大,运行速度下降明显。比如有200个数据数组等待比较,每次都要比较很多次。
+
+经常可以看到有的工程里`switch`里面有上百个`case strcmp():`,极度影响代码运行效率。
+
+此时,将key的数组特征化,计算出特有的hash值,来代替比较,就可以给运行速度带来很大的提升。
+
+## HASH算法
+
+hash-match库中提供了一种哈希算法:[Murmurhash3](https://github.com/aappleby/smhasher)
+
+MurmurHash是一种非加密函数的哈希函数,它能够产生出32-bit或128-bit哈希值。自称超级快的hash算法,是FNV的4-5倍。
+
+MurmurHash算法由Austin Appleby创建于2008年,现已应用到Hadoop、libstdc 、nginx、libmemcached,Redis,Memcached,Cassandra,HBase,Lucene等开源系统。
+
+用户可以移植其他匹配算法,通过更改`hash_match_caculate`宏定义决定使用哪一种。
+
+## 使用方法
+
+库中头文件参照了rt-thread中针对不同的编译器设置了不同的宏定义,目前支持MDK、IAR和GNU gcc。其他编译器暂未移植,一般来说已经满足使用。如果有其他编译器需求,请自行移植。
+
+使用中只需要2个API函数和一个数据定义宏
+
+```c
+HASH_MATCH_EXPORT(GROUP, NAME, hash_key_src, hash_key_len, handler, ...);
+```
+
+使用`HASH_MATCH_EXPORT`定义数据参数定义到指定代码段
+
+```c
+HASH_MATCH_INIT(GROUP);
+```
+
+使用`HASH_MATCH_INIT`将初始化整个组内的哈希值
+
+```c
+HASH_MATCH(GROUP, SRC, LEN, PARAMS);
+```
+
+使用`HASH_MATCH`将对提供的key进行哈希匹配
+
+### MDK和IAR编译器使用方法
+
+MDK和IAR中都在软件内部进行更改了代码编译后的链接操作,可以很方便的使用,无需修改工程文件。
+
+#### GROUP命名
+
+选择一个GROUP名字,例如hash_match_test
+
+#### 注册命令
+
+使用该名字定义该组下的所有命令,定义应当为全局变量定义,即放在函数外部
+
+```c
+HASH_MATCH_EXPORT(hash_match_test, hash_match_test1, hash_match_test1key, sizeof(hash_match_test1key), hash_match_test1func, "this is test 1");
+```
+
+#### 初始化GROUP
+
+```c
+HASH_MATCH_INIT(hash_match_test);
+```
+
+#### 匹配key
+
+```c
+HASH_MATCH(hash_match_test, hash_match_test1key, sizeof(hash_match_test1key), NULL);
+```
+
+### GUN gcc编译器使用方法
+
+GUN gcc工程需要在工程的ld文件中找到非零变量的初始化链接代码。
+
+hash-match具有分组信息,即使用时的GROUP参数。
+
+在gnu gcc编译器时,通过宏定义展开,每个GROUP定义的const常量都会被放到__attribute__((section("GROUP")))中
+
+例如,应用代码中串口有命令需要处理,将GROUP参数传入为uart,则const常量会被放到__attribute__((section("uart")))中
+
+而gnu gcc编译器并没有在链接代码操作中有自定义的操作
+
+所以根据不同的GROUP,在ld文件的`.text`段中添加代码,本例子将以GROUP参数为hash_match_test为例子
+
+```ld
+. = ALIGN(4);
+PROVIDE(hash_match_test_start = .);
+KEEP(*(hash_match_test))
+PROVIDE(hash_match_test_end = .);
+. = ALIGN(4);
+```
+
+例如:
+
+```ld
+.text :
+{
+    . = ALIGN(4);
+    KEEP(*(SORT_NONE(.handle_reset)))
+    *(.text)
+    *(.text.*)
+    *(.rodata)
+    *(.rodata*)
+    *(.sdata2.*)
+    *(.glue_7)
+    *(.glue_7t)
+    *(.gnu.linkonce.t.*)
+    . = ALIGN(4);
+
+    /* this is for GROUP hash_match_test of hash_match library. */
+    PROVIDE(hash_match_test_start = .);
+    KEEP(*(hash_match_test))
+    PROVIDE(hash_match_test_end = .);
+    . = ALIGN(4);
+
+} >FLASH AT>FLASH 
+```
+
+代码中使用了几个GROUP,就需要在ld中添加几个相关代码,其他步骤和MDK和IAR编译器使用方法一致
+
+## 配置选项
+
+配置选项可以在`hash-match.h`中修改
+
+```c
+/*
+ * @Note: hash-match use murmur3 hash algorithm in default: https://github.com/aappleby/smhasher.
+ *        you can use your own hash algorithm by change the definition "hash_match_caculate".
+ */
+#define hash_match_caculate         murmurhash3_caculate32
+
+/* whether save description of hash source or not, set 0 will not save description. */
+#define HASH_MATCH_SAVE_DESC        0
+
+/* set HASH_MATCH_INIT_CHECK to 1 will check all hash values in one group during init a group, report if some hash value is duplicated. */
+#define HASH_MATCH_INIT_CHECK       0
+
+/* change to your own printf function, or don't use it. */
+#define HASH_MATCH_PRINTF           printf
+
+/* whether compare key when hash_code is same. */
+#define HASH_MATCH_COMPARE_KEY      1
+
+/* use string.h or self functions to compare key. */
+#define HASH_MATCH_USE_STRING_H     1
+
+#if HASH_MATCH_USE_STRING_H
+    #include "string.h"
+    #define hash_match_memcmp       memcmp
+    #define HASH_MATCH_MEMCMP_SAME  0
+#else
+    #define hash_match_memcmp
+    #define HASH_MATCH_MEMCMP_SAME
+#endif
+```
+
+`hash_match_caculate`宏定义决定了`hash-match`采用的哈希算法,移植如需要改为自己的算法,请按照`uint32_t murmurhash3_caculate32(const void *hash_key, uint32_t len);`函数接口实现。
+
+`HASH_MATCH_SAVE_DESC`宏定义决定了是否会保存描述,设置为非0就会启用。
+
+`HASH_MATCH_INIT_CHECK`宏定义决定在初始化时,是否和已经计算得到的其他哈希值进行比较,如果有相同的哈希值,则报错。
+
+`HASH_MATCH_PRINTF`宏定义是在有报错信息时候调用的打印函数。
+
+`HASH_MATCH_COMPARE_KEY`宏定义决定了在哈希值匹配成功后,是否继续匹配数据内容。一般来说,长度一样的数据内容,哈希值一样的概率小的微乎其微,所以可以根据安全性要求来决定是否继续匹配数据内容。
+
+`HASH_MATCH_USE_STRING_H`宏定义决定了匹配数据内容使用的函数,如果不准备使用,可以改为其他函数。
+
+## 注意事项
+
+虽然头文件中提供了函数,但是一般不直接使用那些函数,因为需要根据不同编译器有不同的配置,所以此时需要使用宏定义的函数来对不同编译器产生适用性。
+
+库中头文件参照了rt-thread中针对不同的编译器设置了不同的宏定义,目前支持MDK、IAR和GNU gcc。其他编译器暂未移植,一般来说已经满足使用。如果有其他编译器需求,请自行移植。
+
+hash-match没有使用可变参数传递,匹配回调函数只携带了一个参数`void *`。
+
+## 示例程序
+
+rt-thread移植例程:
+
+[examples/hash_match_demo.c](https://github.com/smartmx/hash-match/tree/main/examples/hash_match_demo.c)。
+
+可以通过`RT-Thread menuconfig`方式,将文件添加至工程:
+
+```c
+RT-Thread online packages  --->
+    tools packages  --->
+        [*] hash-match: using hashmap on MCUs  --->
+        [*]   Enable hash match demo
+              version (latest)  --->
+```
+
+## 版权许可
+
+hash-match 遵循 Apache License v2.0 开源协议。
+
+欢迎大家提交PR时将自己的版权信息添加到文件头部,并且在change log中附上自己的修改日志。
+
+## [博客主页](https://blog.maxiang.vip/)