-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement map that is MISRA compliant
- MISRA compliant map
- Loading branch information
1 parent
6df02d0
commit 4a0de3e
Showing
6 changed files
with
307 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
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; | ||
} | ||
} | ||
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) { | ||
/* -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); | ||
/* -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; | ||
} | ||
} 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; | ||
} | ||
} | ||
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) { | ||
/* -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; | ||
} | ||
} | ||
return status; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} |