Skip to content

Commit

Permalink
Implement map that is MISRA compliant
Browse files Browse the repository at this point in the history
- MISRA compliant map
  • Loading branch information
jciberlin committed Oct 7, 2023
1 parent 67a5ed9 commit e6e86cc
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 0 deletions.
87 changes: 87 additions & 0 deletions Inc/map.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/****************************************************************************
*
* Copyright (c) 2023 IMProject Development Team. All rights reserved.
* Authors: Juraj Ciberlin <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name IMProject nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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 UTILITY_MAP_H_
#define UTILITY_MAP_H_

#include "typedefs.h"

typedef struct {
byte_t* keys;
byte_t* values;
int32_t key_size;
int32_t value_size;
int32_t max_map_size;
int32_t current_size;
bool initialized;
} Map_t;

/**
* @brief Initialize map.
*
* @param[out] *map Pointer to the map (type Map_t).
* @param[in] *keys Pointer to keys in the map.
* @param[in] *values Pointer to values in the map.
* @param[in] key_size Size of the key in the map.
* @param[in] value_size Size of the value in the map.
* @param[in] max_map_size Max size of the map.
*
* @return True if map is successfully initialized, otherwise false.
*/
bool Map_initMap(Map_t* map, byte_t* keys, byte_t* values, int32_t key_size, int32_t value_size,
int32_t max_map_size);

/**
* @brief Insert new element in the map.
*
* @param[in/out] *map Pointer to the map (type Map_t).
* @param[in] *key Pointer to the key that will be inserted in the map.
* @param[in] *value Pointer to the value that will be inserted in the map.
*
* @return True if new element is successfully inserted in the map, otherwise false.
*/
bool Map_insert(Map_t* map, const byte_t* key, const byte_t* value);

/**
* @brief Get a value from the map using the key.
*
* @param[in] *map Pointer to the map (type Map_t).
* @param[in] *key Pointer to the key.
* @param[out] *value Pointer to the value that is mapped with the particular key.
*
* @return True if the value is successfully gotten using the key, otherwise false.
*/
bool Map_getValue(const Map_t* map, const byte_t* key, byte_t* value);

#endif /* UTILITY_MAP_H_ */
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ IMUTILITY_FILES=\
Src/crc/crc32_variants/crc32_xfer.c \
Src/heap_sort.c \
Src/json.c \
Src/map.c \
Src/priority_queue.c \
Src/queue.c \
Src/scheduler.c \
Expand All @@ -124,6 +125,7 @@ SRC_FILES+=$(IMUTILITY_FILES) \
Tests/test_crc32.c \
Tests/test_heap_sort.c \
Tests/test_json.c \
Tests/test_map.c \
Tests/test_priority_queue.c \
Tests/test_queue.c \
Tests/test_scheduler.c \
Expand Down
105 changes: 105 additions & 0 deletions Src/map.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/****************************************************************************
*
* Copyright (c) 2023 IMProject Development Team. All rights reserved.
* Authors: Juraj Ciberlin <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name IMProject nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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.
*
****************************************************************************/

#include "map.h"

#include <string.h>

#define INDEX_NOT_FOUND (-1)

static int32_t
Map_findIndex(const Map_t* map, const byte_t* key, int32_t size) {
int32_t index = INDEX_NOT_FOUND;
for (int32_t i = 0; i < size; ++i) {
if (memcmp(&map->keys[i * map->key_size], key, map->key_size) == 0) {
index = i;
break;
}
}
return index;
}

bool
Map_initMap(Map_t* map, byte_t* keys, byte_t* values, int32_t key_size, int32_t value_size,
int32_t max_map_size) {
bool status = false;
if ((key_size != 0) && (value_size != 0) && (max_map_size != 0) && (keys != NULL_PTR) && (values != NULL_PTR)) {
map->keys = keys;
map->values = values;
map->key_size = key_size;
map->value_size = value_size;
map->max_map_size = max_map_size;
map->current_size = 0;
map->initialized = true;
status = true;
}
return status;
}

bool
Map_insert(Map_t* map, const byte_t* key, const byte_t* value) {
bool status = false;
if ((map != NULL_PTR) && (map->initialized)) {
int32_t index = Map_findIndex(map, key, map->current_size);
if (index == INDEX_NOT_FOUND) {
if (map->current_size != map->max_map_size) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&map->keys[map->current_size * map->key_size], key, map->key_size);
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&map->values[map->current_size * map->value_size], value, map->value_size);
++map->current_size;
status = true;
}
} else {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&map->values[index * map->value_size], value, map->value_size);
status = true;
}
}
return status;
}

bool
Map_getValue(const Map_t* map, const byte_t* key, byte_t* value) {
bool status = false;
if ((map != NULL_PTR) && (map->initialized)) {
int32_t index = Map_findIndex(map, key, map->current_size);
if (index != INDEX_NOT_FOUND) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(value, &map->values[index * map->value_size], map->value_size);
status = true;
}
}
return status;
}
1 change: 1 addition & 0 deletions Tests/test_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ RunAllTests(void) {
RUN_TEST_GROUP(Crc32);
RUN_TEST_GROUP(HeapSort);
RUN_TEST_GROUP(Json);
RUN_TEST_GROUP(Map);
RUN_TEST_GROUP(PriorityQueue);
RUN_TEST_GROUP(Queue);
RUN_TEST_GROUP(Scheduler);
Expand Down
94 changes: 94 additions & 0 deletions Tests/test_map.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "map.h"

#include <string.h>

#include "unity.h"
#include "unity_fixture.h"

TEST_GROUP(Map);

TEST_SETUP(Map) {
}

TEST_TEAR_DOWN(Map) {
}

TEST_GROUP_RUNNER(Map) {
RUN_TEST_CASE(Map, Map_uint32_key_char_value);
RUN_TEST_CASE(Map, Map_int32_key_fp32_value);
RUN_TEST_CASE(Map, Map_negative_cases);
}

TEST(Map, Map_uint32_key_char_value) {
uint32_t keys[100];
char values[100][50];
Map_t map;
TEST_ASSERT_TRUE(Map_initMap(&map, (byte_t*)keys, (byte_t*)values, sizeof(keys[0]), sizeof(values[0]),
sizeof(keys) / sizeof(keys[0])));

uint32_t key = 2U;
char value1[] = "Value1";
TEST_ASSERT_TRUE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value1));
key = 3U;
char value2[] = "Value2";
TEST_ASSERT_TRUE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value2));

char foundValue[50];
key = 2U;
TEST_ASSERT_TRUE(Map_getValue(&map, (byte_t*)&key, (byte_t*)&foundValue));
TEST_ASSERT_TRUE(0 == strcmp(&foundValue[0], "Value1"));
}

TEST(Map, Map_int32_key_fp32_value) {
int32_t keys[2];
float32_t values[2];
Map_t map;
TEST_ASSERT_TRUE(Map_initMap(&map, (byte_t*)keys, (byte_t*)values, sizeof(keys[0]), sizeof(values[0]),
sizeof(keys) / sizeof(keys[0])));

int32_t key = 1;
float32_t value = 10.5F;
TEST_ASSERT_TRUE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value));
key = 2;
value = 15.4F;
TEST_ASSERT_TRUE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value));

float32_t foundValue;
TEST_ASSERT_TRUE(Map_getValue(&map, (byte_t*)&key, (byte_t*)&foundValue));
TEST_ASSERT_EQUAL_FLOAT(foundValue, 15.4F);

value = 300.1F;
TEST_ASSERT_TRUE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value));
TEST_ASSERT_TRUE(Map_getValue(&map, (byte_t*)&key, (byte_t*)&foundValue));
TEST_ASSERT_EQUAL_FLOAT(foundValue, 300.1F);

key = 10;
TEST_ASSERT_FALSE(Map_getValue(&map, (byte_t*)&key, (byte_t*)&foundValue));

TEST_ASSERT_FALSE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value));
}

TEST(Map, Map_negative_cases) {
int32_t keys[5];
float32_t values[5];
Map_t map;

TEST_ASSERT_FALSE(Map_initMap(&map, (byte_t*)keys, (byte_t*)values, 0, sizeof(values[0]),
sizeof(keys) / sizeof(keys[0])));
TEST_ASSERT_FALSE(Map_initMap(&map, (byte_t*)keys, (byte_t*)values, sizeof(keys[0]), 0,
sizeof(keys) / sizeof(keys[0])));
TEST_ASSERT_FALSE(Map_initMap(&map, (byte_t*)keys, (byte_t*)values, sizeof(keys[0]), sizeof(values[0]),
0));
TEST_ASSERT_FALSE(Map_initMap(&map, NULL_PTR, (byte_t*)values, sizeof(keys[0]), sizeof(values[0]),
sizeof(keys) / sizeof(keys[0])));
TEST_ASSERT_FALSE(Map_initMap(&map, (byte_t*)keys, NULL_PTR, sizeof(keys[0]), sizeof(values[0]),
sizeof(keys) / sizeof(keys[0])));

int32_t key = 1;
float32_t value = 10.5F;
TEST_ASSERT_FALSE(Map_insert(&map, (byte_t*)&key, (byte_t*)&value));
TEST_ASSERT_FALSE(Map_insert(NULL_PTR, (byte_t*)&key, (byte_t*)&value));

TEST_ASSERT_FALSE(Map_getValue(&map, (byte_t*)&key, (byte_t*)&value));
TEST_ASSERT_FALSE(Map_getValue(NULL_PTR, (byte_t*)&key, (byte_t*)&value));
}

0 comments on commit e6e86cc

Please sign in to comment.