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 3712cce
Show file tree
Hide file tree
Showing 6 changed files with 307 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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ Join us on the Discord channel https://discord.gg/R6nZxZqDH3
- Json_endString
- Json_findByKey

### Map
- Map_initMap
- Map_insert
- Map_getValue

### Priority queue
- PriorityQueue_initQueue
- PriorityQueue_isEmpty
Expand Down
118 changes: 118 additions & 0 deletions Src/map.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/****************************************************************************
*
* 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;

Check warning on line 43 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L42-L43

Added lines #L42 - L43 were not covered by tests
for (int32_t i = 0; i < size; ++i) {
/* -E> compliant MC3R1.R21.18 1 map->key_size is a size of the key in the map and it has appropriate value. */
if (memcmp(&map->keys[i * map->key_size], key, (size_t)map->key_size) == 0) {
index = i;
break;

Check warning on line 48 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L47-L48

Added lines #L47 - L48 were not covered by tests
}
}
return index;

Check warning on line 51 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L51

Added line #L51 was not covered by tests
}

bool
Map_initMap(Map_t* map, byte_t* keys, byte_t* values, int32_t key_size, int32_t value_size,

Check warning on line 55 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L55

Added line #L55 was not covered by tests
int32_t max_map_size) {
bool status = false;

Check warning on line 57 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L57

Added line #L57 was not covered by tests
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;

Check warning on line 66 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L59-L66

Added lines #L59 - L66 were not covered by tests
}
return status;

Check warning on line 68 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L68

Added line #L68 was not covered by tests
}

bool
Map_insert(Map_t* map, const byte_t* key, const byte_t* value) {
bool status = false;

Check warning on line 73 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L72-L73

Added lines #L72 - L73 were not covered by tests
if ((map != NULL_PTR) && (map->initialized)) {
int32_t index = Map_findIndex(map, key, map->current_size);

Check warning on line 75 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L75

Added line #L75 was not covered by tests
if (index == INDEX_NOT_FOUND) {
if (map->current_size != map->max_map_size) {
/* -E> compliant MC3R1.R21.18 4 map->key_size is a size of the key in the map and it has appropriate value. */
/* -E> compliant MC3R1.R19.1 3 Overlap will not happen because there is a check if current map size reached
* 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, (size_t)map->key_size);

Check warning on line 82 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L82

Added line #L82 was not covered by tests
/* -E> compliant MC3R1.R21.18 4 map->value_size is a size of the value in the map and it has appropriate value. */
/* -E> compliant MC3R1.R19.1 3 Overlap will not happen because there is a check if current map size reached
* max map 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, (size_t)map->value_size);
++map->current_size;
status = true;

Check warning on line 89 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L87-L89

Added lines #L87 - L89 were not covered by tests
}
} else {
/* -E> compliant MC3R1.R21.18 4 map->value_size is a size of the value in the map and it has appropriate value. */
/* -E> compliant MC3R1.R19.1 3 Overlap will not happen since the current key is the same as the key that is
* previously inserted in the map. Therefore, new value will be mapped to that key. */
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&map->values[index * map->value_size], value, (size_t)map->value_size);
status = true;

Check warning on line 97 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L96-L97

Added lines #L96 - L97 were not covered by tests
}
}
return status;

Check warning on line 100 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L100

Added line #L100 was not covered by tests
}

bool
Map_getValue(const Map_t* map, const byte_t* key, byte_t* value) {
bool status = false;

Check warning on line 105 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L104-L105

Added lines #L104 - L105 were not covered by tests
if ((map != NULL_PTR) && (map->initialized)) {
int32_t index = Map_findIndex(map, key, map->current_size);

Check warning on line 107 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L107

Added line #L107 was not covered by tests
if (index != INDEX_NOT_FOUND) {
/* -E> compliant MC3R1.R21.18 4 map->value_size is a size of the value in the map and it has appropriate value. */
/* -E> compliant MC3R1.R19.1 3 Overlap will not happen because the map->value_size is the size of the value
* and every element in map->values has that size */
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(value, &map->values[index * map->value_size], (size_t)map->value_size);
status = true;

Check warning on line 114 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L113-L114

Added lines #L113 - L114 were not covered by tests
}
}
return status;

Check warning on line 117 in Src/map.c

View check run for this annotation

Codecov / codecov/patch

Src/map.c#L117

Added line #L117 was not covered by tests
}
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 3712cce

Please sign in to comment.