Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Inc/sort/bubble_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
#include "typedefs.h"

/**
* @brief Sort elements using bubble sort algorithm.
* @brief Sort elements using bubble sort algorithm. It compares the adjacent elements and swaps them
* if they are in the wrong order. It is done repeatedly until all elements are sorted.
* Time complexity: O(N^2)
*
* @param[in/out] *buffer Pointer to the buffer that contains elements that will be sorted.
* @param[in] number_of_elements Number of elements in the buffer.
Expand Down
5 changes: 4 additions & 1 deletion Inc/sort/heap_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
#include "typedefs.h"

/**
* @brief Sort elements using heap sort algorithm.
* @brief Sort elements using heap sort algorithm. It uses heapify to convert array into max heap.
* It deletes the root node of the max heap (one by one) and replaces it with the last node. After that,
* heapify is done again. Whole process is repeated while heap size is greater than 1.
* Time complexity: O(N log N)
*
* @param[in/out] *buffer Pointer to the buffer that contains elements that will be sorted.
* @param[in] number_of_elements Number of elements in the buffer.
Expand Down
8 changes: 5 additions & 3 deletions Inc/sort/insertion_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
#define MAX_ELEMENT_SIZE (64)

/**
* @brief Sort elements using insertion sort algorithm. Insertion sort algorithm is a simple
* sorting algorithm that has O(N^2) time complexity. It is efficient on smaller lists, and
* much less efficient on large lists.
* @brief Sort elements using insertion sort algorithm. Divide given list into sorted and unsorted part
* (first element is considered sorted). Iterate through each element in the unsorted part. Pick one
* element at a time, and insert it into correct position in the sorted part. It is efficient on smaller
* lists, and much less efficient on large lists.
* Time complexity: O(N^2)
*
* NOTE: implemented that the max element size is 64 B. If element size is larger, then
* MAX_ELEMENT_SIZE macro must be updated.
Expand Down
59 changes: 59 additions & 0 deletions Inc/sort/merge_sort.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/****************************************************************************
*
* Copyright (c) 2025 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_MERGE_SORT_H_
#define UTILITY_MERGE_SORT_H_

#include "typedefs.h"

#define MAX_HALVES_SIZE (64)

/**
* @brief Sort elements using merge sort algorithm. Merge sort algorithm works on a principle that it
* divides the list/array into two halves. Sort each one. Merge them back together. Repeat the whole
* process until the entire array is sorted. This algorithm does not use recursion since it is not MISRA
* compliant.
* Time complexity: O(N log N)
*
* @param[in/out] *buffer Pointer to the buffer that contains elements that will be sorted.
* @param[in] number_of_elements Number of elements in the buffer.
* @param[in] element_size Size of the element, in bytes.
* @param[in] *compareFun Pointer to compare function. Compare function has two parameters (pointer to
* first element and pointer to second element). As a result, it returns boolean,
* true if first element is greater than second element, otherwise false.
*/
void MergeSort_sort(byte_t* buffer, int32_t number_of_elements, int32_t element_size,
bool (*compareFun)(void* first, void* second));

#endif /* UTILITY_MERGE_SORT_H_ */
4 changes: 2 additions & 2 deletions Inc/sort/selection_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
#include "typedefs.h"

/**
* @brief Sort elements using selection sort algorithm. Selection sort algorithm is an in-place
* comparison sorting algorithm that has O(N^2) time complexity. It divides the input array into
* @brief Sort elements using selection sort algorithm. It divides the input array into
* two parts, sorted sub-array of items which is built up from left to right and unsorted items
* that occupies the rest of the array. The sorted sub-array is empty and the unsorted sub-array
* is the entire input array. The algorithm proceeds by finding the smallest element in the
* unsorted sub-array, swapping it with the leftmost unsorted element (putting it in sorted order),
* and moving the sub-array boundaries one element to the right.
* Time complexity: O(N^2)
*
* @param[in/out] *buffer Pointer to the buffer that contains elements that will be sorted.
* @param[in] number_of_elements Number of elements in the buffer.
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ IMUTILITY_FILES=\
Src/sort/bubble_sort.c \
Src/sort/heap_sort.c \
Src/sort/insertion_sort.c \
Src/sort/merge_sort.c \
Src/sort/selection_sort.c \
Src/json.c \
Src/map.c \
Expand All @@ -136,6 +137,7 @@ SRC_FILES+=$(IMUTILITY_FILES) \
Tests/test_insertion_sort.c \
Tests/test_json.c \
Tests/test_map.c \
Tests/test_merge_sort.c \
Tests/test_priority_queue.c \
Tests/test_queue.c \
Tests/test_scheduler.c \
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Join us on the Discord channel https://discord.gg/R6nZxZqDH3
- BubbleSort_sort
- HeapSort_sort
- InsertionSort_sort
- MergeSort_sort
- SelectionSort_sort

### Utils
Expand Down
8 changes: 0 additions & 8 deletions Src/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ Json_startString(char* buffer, size_t buffer_size) {
bool success = false;

if (buffer_size >= MINIMAL_SIZE) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[0], "{");
success = true;
}
Expand All @@ -59,25 +58,19 @@ Json_addData(char* buffer, size_t buffer_size, const char* key, const char* valu
size_t total_size = strlen("\"\":\"\"") + strlen(key) + strlen(value) + 1U;

if (0 == strcmp(&buffer[index - 1U], "\"")) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], ",");
++index;
}

if ((total_size + index) <= buffer_size) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], "\"");
index += strlen("\"");
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], key);
index += strlen(key);
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], "\":\"");
index += strlen("\":\"");
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], value);
index += strlen(value);
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], "\"");

success = true;
Expand All @@ -92,7 +85,6 @@ Json_endString(char* buffer, size_t buffer_size) {

size_t index = strlen(buffer);
if (buffer_size >= (MINIMAL_SIZE + index)) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case, therefore it is not used
strcpy(&buffer[index], "}");
success = true;
}
Expand Down
4 changes: 0 additions & 4 deletions Src/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,12 @@ Map_insert(Map_t* map, const byte_t* key, const byte_t* value) {
int32_t index = GetIndex(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, (size_t)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, (size_t)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, (size_t)map->value_size);
status = true;
}
Expand All @@ -95,7 +92,6 @@ Map_getValue(const Map_t* map, const byte_t* key, byte_t* value) {
if (map != NULL_PTR) {
int32_t index = GetIndex(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], (size_t)map->value_size);
status = true;
}
Expand Down
5 changes: 0 additions & 5 deletions Src/priority_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ PriorityQueue_enqueue(PriorityQueue_t* queue, const PriorityQueueItem_t* item) {
bool status = false;
if (!Full(queue)) {
uint8_t* buffer = queue->buffer;
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&buffer[queue->size * queue->element_size], item->element, queue->element_size);
queue->priority_array[queue->size] = *(item->priority);
queue->size = queue->size + 1U;
Expand All @@ -109,12 +108,10 @@ PriorityQueue_enqueue(PriorityQueue_t* queue, const PriorityQueueItem_t* item) {
queue->size = queue->size - 1U;
const uint32_t current_size = queue->size;
for (uint32_t i = lowest_priority_index; i < current_size; ++i) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&buffer[i * queue->element_size], &buffer[(i * queue->element_size) + queue->element_size],
queue->element_size);
queue->priority_array[i] = queue->priority_array[i + 1U];
}
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&buffer[queue->size * queue->element_size], item->element, queue->element_size);
queue->priority_array[queue->size] = *(item->priority);
queue->size = queue->size + 1U;
Expand All @@ -130,12 +127,10 @@ PriorityQueue_dequeue(PriorityQueue_t* queue, uint8_t* element) {
status = true;
uint32_t highest_priority_index = GetHighestPriorityIndex(queue);
uint8_t* buffer = queue->buffer;
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(element, &buffer[highest_priority_index * queue->element_size], queue->element_size);
queue->size = queue->size - 1U;
const uint32_t current_size = queue->size;
for (uint32_t i = highest_priority_index; i < current_size; ++i) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&buffer[i * queue->element_size], &buffer[(i * queue->element_size) + queue->element_size],
queue->element_size);
queue->priority_array[i] = queue->priority_array[i + 1U];
Expand Down
4 changes: 0 additions & 4 deletions Src/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ Queue_enqueue(Queue_t* queue, const uint8_t* element) {
if ((queue != NULL_PTR) && (element != NULL_PTR)) {
if (!Queue_full(queue)) {
uint8_t* buffer = queue->buffer;
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&buffer[((queue->rear + 1U) % queue->capacity) * queue->element_size], element, queue->element_size);
queue->rear = (queue->rear + 1U) % queue->capacity;
queue->size = queue->size + 1U;
Expand All @@ -83,7 +82,6 @@ Queue_dequeue(Queue_t* queue, uint8_t* element) {
if ((queue != NULL_PTR) && (element != NULL_PTR)) {
if (!Queue_empty(queue)) {
const uint8_t* buffer = (const uint8_t*)queue->buffer;
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(element, &buffer[queue->front * queue->element_size], queue->element_size);
queue->front = (queue->front + 1U) % queue->capacity;
queue->size = queue->size - 1U;
Expand All @@ -99,7 +97,6 @@ Queue_front(const Queue_t* queue, uint8_t* element) {
if ((queue != NULL_PTR) && (element != NULL_PTR)) {
if (!Queue_empty(queue)) {
const uint8_t* buffer = (const uint8_t*)queue->buffer;
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(element, &buffer[queue->front * queue->element_size], queue->element_size);
status = true;
}
Expand All @@ -113,7 +110,6 @@ Queue_rear(const Queue_t* queue, uint8_t* element) {
if ((queue != NULL_PTR) && (element != NULL_PTR)) {
if (!Queue_empty(queue)) {
const uint8_t* buffer = (const uint8_t*)queue->buffer;
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(element, &buffer[queue->rear * queue->element_size], queue->element_size);
status = true;
}
Expand Down
3 changes: 0 additions & 3 deletions Src/sort/insertion_sort.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,16 @@ InsertionSort_sort(byte_t* buffer, int32_t number_of_elements, int32_t element_s
byte_t* element = &max_element[0];

for (int32_t i = 1; i < number_of_elements; ++i) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(element, &elements[i * element_size], (size_t)element_size);

int32_t j = i - 1;
bool compare = compareFun(&elements[j * element_size], element);

while ((j >= 0) && compare) {
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&elements[(j + 1) * element_size], &elements[j * element_size], (size_t)element_size);
--j;
compare = compareFun(&elements[j * element_size], element);
}
// cppcheck-suppress misra-c2012-17.7; return value is not needed in this case
memcpy(&elements[(j + 1) * element_size], element, (size_t)element_size);
}
}
104 changes: 104 additions & 0 deletions Src/sort/merge_sort.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/****************************************************************************
*
* Copyright (c) 2025 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 "merge_sort.h"

#include <string.h>

static void
MergeHalves(byte_t* buffer, int32_t element_size, int32_t left, int32_t mid, int32_t right,
bool (*compareFun)(void* first, void* second)) {
byte_t* elements = buffer;
byte_t left_half[MAX_HALVES_SIZE];
byte_t right_half[MAX_HALVES_SIZE];
int32_t i;
int32_t j;
int32_t k;
int32_t number_of_elements_1 = mid - left + 1;
int32_t number_of_elements_2 = right - mid;

for (i = 0; i < number_of_elements_1; ++i) {
memcpy(&left_half[i * element_size], &elements[(left + i) * element_size], (size_t)element_size);
}

for (j = 0; j < number_of_elements_2; ++j) {
memcpy(&right_half[j * element_size], &elements[(mid + 1 + j) * element_size], (size_t)element_size);
}

i = 0;
j = 0;
k = left;

while ((i < number_of_elements_1) && (j < number_of_elements_2)) {
bool compare = compareFun(&right_half[j * element_size], &left_half[i * element_size]);
if (compare) {
memcpy(&elements[k * element_size], &left_half[i * element_size], (size_t)element_size);
++i;
} else {
memcpy(&elements[k * element_size], &right_half[j * element_size], (size_t)element_size);
++j;
}
++k;
}

while (i < number_of_elements_1) {
memcpy(&elements[k * element_size], &left_half[i * element_size], (size_t)element_size);
++i;
++k;
}

while (j < number_of_elements_2) {
memcpy(&elements[k * element_size], &right_half[j * element_size], (size_t)element_size);
++j;
++k;
}
}

void
MergeSort_sort(byte_t* buffer, int32_t number_of_elements, int32_t element_size,
bool (*compareFun)(void* first, void* second)) {
byte_t* elements = buffer;
for (int32_t current_size = 1; current_size <= number_of_elements - 1; current_size *= 2) {
for (int32_t left = 0; left < number_of_elements - 1; left += (2 * current_size)) {
int32_t compare_first_1 = left + current_size - 1;
int32_t compare_second = number_of_elements - 1;
int32_t mid = (compare_first_1 < compare_second) ? compare_first_1 : compare_second;

int32_t compare_first_2 = left + (2 * current_size) - 1;
int32_t right = (compare_first_2 < compare_second) ? compare_first_2 : compare_second;

MergeHalves(elements, element_size, left, mid, right, compareFun);
}
}
}
Loading
Loading