From 0e46862e6c7adc76d385dfa8b185261efb419974 Mon Sep 17 00:00:00 2001 From: Kevin Peck Date: Thu, 18 Jun 2020 09:15:42 -0400 Subject: [PATCH 1/5] add ability for struct keys --- .gitignore | 2 + README.md | 37 +++ map/map.xcodeproj/project.pbxproj | 297 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + map/map/main.c | 128 ++++++++ src/map.c | 2 +- src/map.h | 1 - src/mapsk.c | 146 +++++++++ src/mapsk.h | 33 ++ 10 files changed, 659 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 map/map.xcodeproj/project.pbxproj create mode 100644 map/map.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 map/map.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 map/map/main.c create mode 100644 src/mapsk.c create mode 100644 src/mapsk.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dd8799 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +map/map.xcodeproj/project.xcworkspace/xcuserdata +map/map.xcodeproj/xcuserdata diff --git a/README.md b/README.md index 805b425..ea9ab2b 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,43 @@ while ((key = map_next(&m, &iter))) { } ``` +## Extended maps for structure type keys + +A user-defined key from struct type is supported with three additional functions. + +Where a user's key type is + +```c +typedef struct myTypeS { + uint8_t a; + int b; +} myType; +``` + +The related functions and their use are as follows to add a map instance + +```c + const myType c = { 0x40, 125}; + + map_int_t m; + map_init(&m); + + map_set_sk(&m, &a, sizeof(myType), 123); +``` + +, to lookup that specify map + +```c + int *val = map_get_sk(&m, &c, sizeof(myType)); +``` + +, and there is the like remove key function + +```c +map_remove_sk(&m, &c, sizeof(myType)); +``` + + ## License This library is free software; you can redistribute it and/or modify it under the terms of the MIT license. See [LICENSE](LICENSE) for details. diff --git a/map/map.xcodeproj/project.pbxproj b/map/map.xcodeproj/project.pbxproj new file mode 100644 index 0000000..769ff71 --- /dev/null +++ b/map/map.xcodeproj/project.pbxproj @@ -0,0 +1,297 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 0F99D0D8249B7B4E00E1F2DC /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F99D0D7249B7B4E00E1F2DC /* main.c */; }; + 0F99D0E2249B7EBC00E1F2DC /* map.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F99D0E0249B7EBC00E1F2DC /* map.c */; }; + 0F99D0E5249B8E1800E1F2DC /* mapsk.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F99D0E3249B8E1800E1F2DC /* mapsk.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0F99D0D2249B7B4E00E1F2DC /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0F99D0D4249B7B4E00E1F2DC /* map */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = map; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F99D0D7249B7B4E00E1F2DC /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 0F99D0DF249B7BD600E1F2DC /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + 0F99D0E0249B7EBC00E1F2DC /* map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = map.c; path = ../../src/map.c; sourceTree = ""; }; + 0F99D0E1249B7EBC00E1F2DC /* map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = map.h; path = ../../src/map.h; sourceTree = ""; }; + 0F99D0E3249B8E1800E1F2DC /* mapsk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mapsk.c; path = ../../src/mapsk.c; sourceTree = ""; }; + 0F99D0E4249B8E1800E1F2DC /* mapsk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mapsk.h; path = ../../src/mapsk.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0F99D0D1249B7B4E00E1F2DC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0F99D0CB249B7B4D00E1F2DC = { + isa = PBXGroup; + children = ( + 0F99D0DF249B7BD600E1F2DC /* README.md */, + 0F99D0D6249B7B4E00E1F2DC /* map */, + 0F99D0D5249B7B4E00E1F2DC /* Products */, + ); + sourceTree = ""; + }; + 0F99D0D5249B7B4E00E1F2DC /* Products */ = { + isa = PBXGroup; + children = ( + 0F99D0D4249B7B4E00E1F2DC /* map */, + ); + name = Products; + sourceTree = ""; + }; + 0F99D0D6249B7B4E00E1F2DC /* map */ = { + isa = PBXGroup; + children = ( + 0F99D0E3249B8E1800E1F2DC /* mapsk.c */, + 0F99D0E4249B8E1800E1F2DC /* mapsk.h */, + 0F99D0D7249B7B4E00E1F2DC /* main.c */, + 0F99D0E0249B7EBC00E1F2DC /* map.c */, + 0F99D0E1249B7EBC00E1F2DC /* map.h */, + ); + path = map; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0F99D0D3249B7B4E00E1F2DC /* map */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0F99D0DB249B7B4E00E1F2DC /* Build configuration list for PBXNativeTarget "map" */; + buildPhases = ( + 0F99D0D0249B7B4E00E1F2DC /* Sources */, + 0F99D0D1249B7B4E00E1F2DC /* Frameworks */, + 0F99D0D2249B7B4E00E1F2DC /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = map; + productName = map; + productReference = 0F99D0D4249B7B4E00E1F2DC /* map */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0F99D0CC249B7B4D00E1F2DC /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1010; + ORGANIZATIONNAME = "Kevin Peck"; + TargetAttributes = { + 0F99D0D3249B7B4E00E1F2DC = { + CreatedOnToolsVersion = 10.1; + }; + }; + }; + buildConfigurationList = 0F99D0CF249B7B4D00E1F2DC /* Build configuration list for PBXProject "map" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 0F99D0CB249B7B4D00E1F2DC; + productRefGroup = 0F99D0D5249B7B4E00E1F2DC /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0F99D0D3249B7B4E00E1F2DC /* map */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 0F99D0D0249B7B4E00E1F2DC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F99D0E5249B8E1800E1F2DC /* mapsk.c in Sources */, + 0F99D0E2249B7EBC00E1F2DC /* map.c in Sources */, + 0F99D0D8249B7B4E00E1F2DC /* main.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0F99D0D9249B7B4E00E1F2DC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 0F99D0DA249B7B4E00E1F2DC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 0F99D0DC249B7B4E00E1F2DC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = GYAG48J958; + HEADER_SEARCH_PATHS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 0F99D0DD249B7B4E00E1F2DC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = GYAG48J958; + HEADER_SEARCH_PATHS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0F99D0CF249B7B4D00E1F2DC /* Build configuration list for PBXProject "map" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F99D0D9249B7B4E00E1F2DC /* Debug */, + 0F99D0DA249B7B4E00E1F2DC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0F99D0DB249B7B4E00E1F2DC /* Build configuration list for PBXNativeTarget "map" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F99D0DC249B7B4E00E1F2DC /* Debug */, + 0F99D0DD249B7B4E00E1F2DC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0F99D0CC249B7B4D00E1F2DC /* Project object */; +} diff --git a/map/map.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/map/map.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..2ae75c8 --- /dev/null +++ b/map/map.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/map/map.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/map/map.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/map/map.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/map/map/main.c b/map/map/main.c new file mode 100644 index 0000000..794a3fb --- /dev/null +++ b/map/map/main.c @@ -0,0 +1,128 @@ +// +// main.c +// map +// +// Created by Kevin Peck on 2020-06-18. +// Copyright © 2020 Kevin Peck. All rights reserved. +// + +#include +#include +#include "../../src/mapsk.h" + +// Basic use of map with string keys +void testBasicMap() { + printf("\nTest basic map\n"); + + map_int_t m; + map_init(&m); + + map_set(&m, "testkeyA", 123); + map_set(&m, "testkeyB", 124); + map_set(&m, "testke", 125); + + int *val = map_get(&m, "testkeyA"); + if (val) { + printf("value: %d\n", *val); + } else { + printf("ERROR 'val == NULL' with 'testkeyA'"); + exit(1); + } + + val = map_get(&m, "testkey"); + if (val) { + printf("ERROR 'val != NULL' with 'testkey'"); + exit(2); + } else { + printf("value not found\n"); + } + + map_deinit(&m); +} + +// Use of map with struct keys that have string serializer for struct key +typedef struct myTypeS { + uint8_t a; + int b; +} myType; + +#define CALC_SERIALIZESTRINGSIZE(type) (sizeof(type)*2 + 1) +char *serialize_myType(const myType* val) { + static char serialize_myTypeBuff[CALC_SERIALIZESTRINGSIZE(myType)]; + sprintf(serialize_myTypeBuff,"%02x%08x",val->a, (int32_t)val->b); + return serialize_myTypeBuff; +} + +typedef map_t(myType) uint_map_t; + +void testStructSerializeMap() { + printf("\nTest map with serializer for struct key\n"); + + const myType a = { 0x40, 123}; + const myType b = { 0x40, 124}; + const myType c = { 0x40, 125}; + + map_int_t m; + map_init(&m); + + map_set(&m, serialize_myType(&a), 123); + map_set(&m, serialize_myType(&b), 124); + map_set(&m, serialize_myType(&c), 125); + + int *val = map_get(&m, serialize_myType(&b)); + if (val) { + printf("value(%s): %d =?= %d\n",serialize_myType(&b), *val, b.b); + } else { + printf("ERROR 'val == NULL' with '%s'", serialize_myType(&b)); + exit(1); + } + + map_deinit(&m); +} + + +void testStructMap() { + printf("\nTest map with struct key\n"); + + const myType a = { 0x40, 123}; + const myType b = { 0x40, 124}; + const myType c = { 0x40, 125}; + + map_int_t m; + map_init(&m); + + map_set_sk(&m, &a, sizeof(myType), 123); + map_set_sk(&m, &b, sizeof(myType), 124); + map_set_sk(&m, &c, sizeof(myType), 125); + + int *val = map_get_sk(&m, &c, sizeof(myType)); + if (val) { + printf("value(%s): %d =?= %d\n",serialize_myType(&c), *val, c.b); + } else { + printf("ERROR 'val == NULL' with '%s'", serialize_myType(&c)); + exit(1); + } + + map_remove_sk(&m, &c, sizeof(myType)); + + val = map_get_sk(&m, &c, sizeof(myType)); + if (val) { + printf("value(%s): %d =?= %d\n",serialize_myType(&c), *val, c.b); + printf("ERROR 'val != NULL' with '%s'", serialize_myType(&c)); + exit(1); + } else { + printf("value not found (%s)\n", serialize_myType(&c)); + } + map_deinit(&m); +} + +int main(int argc, const char * argv[]) { + + testBasicMap(); + testStructSerializeMap(); + testStructMap(); + + return 0; +} + + diff --git a/src/map.c b/src/map.c index 308ccad..62a7bd2 100644 --- a/src/map.c +++ b/src/map.c @@ -29,7 +29,7 @@ static unsigned map_hash(const char *str) { static map_node_t *map_newnode(const char *key, void *value, int vsize) { map_node_t *node; - int ksize = strlen(key) + 1; + int ksize = (int)strlen(key) + 1; int voffset = ksize + ((sizeof(void*) - ksize) % sizeof(void*)); node = malloc(sizeof(*node) + voffset + vsize); if (!node) return NULL; diff --git a/src/map.h b/src/map.h index 71af710..8020f9a 100644 --- a/src/map.h +++ b/src/map.h @@ -25,7 +25,6 @@ typedef struct { map_node_t *node; } map_iter_t; - #define map_t(T)\ struct { map_base_t base; T *ref; T tmp; } diff --git a/src/mapsk.c b/src/mapsk.c new file mode 100644 index 0000000..38b9876 --- /dev/null +++ b/src/mapsk.c @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2020 kpishere + * + * with credits to : Copyright (c) 2014 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "mapsk.h" + +struct map_node_t { + unsigned hash; + void *value; + map_node_t *next; + /* char key[]; */ + /* char value[]; */ +}; + +static unsigned map_hash_sk(const void *key, int ksize) { + unsigned hash = 5381; + for(int i=0; ihash = map_hash_sk(key, ksize); + node->value = ((char*) (node + 1)) + voffset; + memcpy(node->value, value, vsize); + return node; +} + +static int map_bucketidx(map_base_t *m, unsigned hash) { + /* If the implementation is changed to allow a non-power-of-2 bucket count, + * the line below should be changed to use mod instead of AND */ + return hash & (m->nbuckets - 1); +} + +static void map_addnode(map_base_t *m, map_node_t *node) { + int n = map_bucketidx(m, node->hash); + node->next = m->buckets[n]; + m->buckets[n] = node; +} + +static int map_resize(map_base_t *m, int nbuckets) { + map_node_t *nodes, *node, *next; + map_node_t **buckets; + int i; + /* Chain all nodes together */ + nodes = NULL; + i = m->nbuckets; + while (i--) { + node = (m->buckets)[i]; + while (node) { + next = node->next; + node->next = nodes; + nodes = node; + node = next; + } + } + /* Reset buckets */ + buckets = realloc(m->buckets, sizeof(*m->buckets) * nbuckets); + if (buckets != NULL) { + m->buckets = buckets; + m->nbuckets = nbuckets; + } + if (m->buckets) { + memset(m->buckets, 0, sizeof(*m->buckets) * m->nbuckets); + /* Re-add nodes to buckets */ + node = nodes; + while (node) { + next = node->next; + map_addnode(m, node); + node = next; + } + } + /* Return error code if realloc() failed */ + return (buckets == NULL) ? -1 : 0; +} + +static map_node_t **map_getref_sk(map_base_t *m, const void *key, int ksize) { + unsigned hash = map_hash_sk(key, ksize); + map_node_t **next; + if (m->nbuckets > 0) { + next = &m->buckets[map_bucketidx(m, hash)]; + while (*next) { + if ((*next)->hash == hash && !memcmp((void*) (*next + 1), key, ksize)) { + return next; + } + next = &(*next)->next; + } + } + return NULL; +} + +void *map_get_sk_(map_base_t *m, const void *key, int ksize) { + map_node_t **next = map_getref_sk(m, key, ksize); + return next ? (*next)->value : NULL; +} + +int map_set_sk_(map_base_t *m, const void *key, int ksize, void *value, int vsize) { + int n, err; + map_node_t **next, *node; + /* Find & replace existing node */ + next = map_getref_sk(m, key, ksize); + if (next) { + memcpy((*next)->value, value, vsize); + return 0; + } + /* Add new node */ + node = map_newnode_sk(key, ksize, value, vsize); + if (node == NULL) goto fail; + if (m->nnodes >= m->nbuckets) { + n = (m->nbuckets > 0) ? (m->nbuckets << 1) : 1; + err = map_resize(m, n); + if (err) goto fail; + } + map_addnode(m, node); + m->nnodes++; + return 0; + fail: + if (node) free(node); + return -1; +} + +void map_remove_sk_(map_base_t *m, const void *key, int ksize) { + map_node_t *node; + map_node_t **next = map_getref_sk(m, key, ksize); + if (next) { + node = *next; + *next = (*next)->next; + free(node); + m->nnodes--; + } +} + diff --git a/src/mapsk.h b/src/mapsk.h new file mode 100644 index 0000000..7aaaedb --- /dev/null +++ b/src/mapsk.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2020 kpishere + * + * with credits to : Copyright (c) 2014 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef MAPSK_H +#define MAPSK_H + +#include +#include "map.h" + +#define map_get_sk(m, key, ksize)\ + ( (m)->ref = map_get_sk_(&(m)->base, (void*)key, ksize) ) + + +#define map_set_sk(m, key, ksize, value)\ + ( (m)->tmp = (value),\ + map_set_sk_(&(m)->base, (void*)key, ksize, &(m)->tmp, sizeof((m)->tmp)) ) + + +#define map_remove_sk(m, key, ksize)\ + map_remove_sk_(&(m)->base, key, ksize) + + +void *map_get_sk_(map_base_t *m, const void *key, int ksize); +int map_set_sk_(map_base_t *m, const void *key, int ksize, void *value, int vsize); +void map_remove_sk_(map_base_t *m, const void *key, int ksize); + +#endif From d48e4f60fcb69efa0bbbaaff1dcc50cf39101b6d Mon Sep 17 00:00:00 2001 From: Kevin Peck Date: Thu, 18 Jun 2020 09:19:15 -0400 Subject: [PATCH 2/5] language update on readme --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ea9ab2b..3c0bb34 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ typedef struct myTypeS { } myType; ``` -The related functions and their use are as follows to add a map instance +The related functions and their use are as follows to add a map instance and mapping with the myType key ```c const myType c = { 0x40, 125}; @@ -128,19 +128,18 @@ The related functions and their use are as follows to add a map instance map_set_sk(&m, &a, sizeof(myType), 123); ``` -, to lookup that specify map +To look that up, you'd use this function ```c int *val = map_get_sk(&m, &c, sizeof(myType)); ``` -, and there is the like remove key function +To remove by that key, there is the like remove key function ```c map_remove_sk(&m, &c, sizeof(myType)); ``` - ## License This library is free software; you can redistribute it and/or modify it under the terms of the MIT license. See [LICENSE](LICENSE) for details. From d3b7bbe4a81ae75cb1558bd44311613f351b2e8e Mon Sep 17 00:00:00 2001 From: Kevin Peck Date: Thu, 18 Jun 2020 09:22:18 -0400 Subject: [PATCH 3/5] consistant credit --- map/map/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/map/map/main.c b/map/map/main.c index 794a3fb..a600999 100644 --- a/map/map/main.c +++ b/map/map/main.c @@ -2,8 +2,8 @@ // main.c // map // -// Created by Kevin Peck on 2020-06-18. -// Copyright © 2020 Kevin Peck. All rights reserved. +// Created by kpishere on 2020-06-18. +// Copyright © 2020 kpishere All rights reserved. // #include @@ -112,7 +112,7 @@ void testStructMap() { exit(1); } else { printf("value not found (%s)\n", serialize_myType(&c)); - } + } map_deinit(&m); } From c3de6412e609f74aeb20f794210efed675a992da Mon Sep 17 00:00:00 2001 From: Kevin Peck Date: Thu, 18 Jun 2020 09:24:15 -0400 Subject: [PATCH 4/5] consistant license --- map/map/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/map/map/main.c b/map/map/main.c index a600999..f6d5cf4 100644 --- a/map/map/main.c +++ b/map/map/main.c @@ -3,7 +3,10 @@ // map // // Created by kpishere on 2020-06-18. -// Copyright © 2020 kpishere All rights reserved. +// Copyright © 2020 kpishere +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the MIT license. See LICENSE for details. // #include From db088966044a2733889840b197cf9921fbf92742 Mon Sep 17 00:00:00 2001 From: Kevin Peck Date: Thu, 18 Jun 2020 14:30:14 -0400 Subject: [PATCH 5/5] added test case for struct value --- map/map/main.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/map/map/main.c b/map/map/main.c index f6d5cf4..f82e336 100644 --- a/map/map/main.c +++ b/map/map/main.c @@ -43,6 +43,51 @@ void testBasicMap() { map_deinit(&m); } +typedef struct { + uint8_t c; + int d; +} myValueType; + +typedef map_t(myValueType) myValueType_map_t; + + +// Basic use of map with string keys and struct type values +void testBasicWStructValMap() { + printf("\nTest basic map with struct type values\n"); + + myValueType_map_t m; + map_init(&m); + + myValueType v1 = { 0x42, 17}; + myValueType v2 = { 0x42, 18}; + myValueType v3 = { 0x42, 19}; + + + map_set(&m, "testkeyA", v1); + map_set(&m, "testkeyB", v2); + map_set(&m, "testke", v3); + + myValueType *val = map_get(&m, "testkeyA"); + if (val) { + printf("value: %02X %d\n", val->c, val->d); + } else { + printf("ERROR 'val == NULL' with 'testkeyA'"); + exit(1); + } + + val = map_get(&m, "testkey"); + if (val) { + printf("ERROR 'val != NULL' with 'testkey'"); + exit(2); + } else { + printf("value not found\n"); + } + + map_deinit(&m); +} + + + // Use of map with struct keys that have string serializer for struct key typedef struct myTypeS { uint8_t a; @@ -122,6 +167,7 @@ void testStructMap() { int main(int argc, const char * argv[]) { testBasicMap(); + testBasicWStructValMap(); testStructSerializeMap(); testStructMap();