diff --git a/lib/convert.c b/lib/convert.c index 7532634..9e535c9 100644 --- a/lib/convert.c +++ b/lib/convert.c @@ -34,22 +34,28 @@ string_t convert_number_to_string(const long long integer) { } bool is_negative = integer < 0; size_t length = 1; - string_t string_value = malloc(sizeof(char) * (length + 1)); + long long current = mathematics_absolute_value(integer); + while (current != 0) { + current = current / 10; + length++; + } + if (is_negative) { + length++; + } + string_t string_value = malloc(sizeof(char) * length); if (string_value == NULL) { exit(EXIT_FAILURE); } - long long current = mathematics_absolute_value(integer); + current = mathematics_absolute_value(integer); + size_t index = 0; while (current != 0) { - character_append(string_value, convert_digit_to_character(current % 10)); + string_value[index++] = convert_digit_to_character(current % 10); current = current / 10; - length++; - string_value = realloc(string_value, sizeof(char) * (length + 1)); } if (is_negative) { - character_append(string_value, '-'); - length++; - string_value = realloc(string_value, sizeof(char) * (length + 1)); + string_value[index++] = '-'; } + string_value[index] = '\0'; return string_reverse(string_value); } @@ -75,6 +81,7 @@ string_t convert_number_from_base_10_to_base(unsigned long long number, unsigned } index_result++; } + result[index_result] = '\0'; return result; } diff --git a/lib/hash_map.c b/lib/hash_map.c index 9d08e0e..cab21e1 100644 --- a/lib/hash_map.c +++ b/lib/hash_map.c @@ -2,75 +2,87 @@ #define ROTATE_LEFT(x, b) (((x) << (b)) | ((x) >> (64 - (b)))) +uint64_t sip_round(uint64_t v0, uint64_t v1, uint64_t v2, uint64_t v3) { + v0 += v1; + v2 += v3; + v1 = ROTATE_LEFT(v1, 13); + v3 = ROTATE_LEFT(v3, 16); + v1 ^= v0; + v3 ^= v2; + v0 = ROTATE_LEFT(v0, 32); + v2 += v1; + v0 += v3; + v1 = ROTATE_LEFT(v1, 17); + v3 = ROTATE_LEFT(v3, 21); + v1 ^= v2; + v3 ^= v0; + v2 = ROTATE_LEFT(v2, 32); + return v0; +} + uint64_t hash(string_t key, size_t capacity) { size_t key_length = string_get_length(key); const uint64_t c = 0x736f6d6570736575; - uint64_t v0 = 0x736f6d6570736575 ^ c; - uint64_t v1 = 0x646f72616e646f6d ^ c; - uint64_t v2 = 0x6c7967656e657261 ^ c; - uint64_t v3 = 0x7465646279746573 ^ c; - uint64_t k1; + uint64_t v0 = c ^ 0x736f6d6570736575; + uint64_t v1 = c ^ 0x646f72616e646f6d; + uint64_t v2 = c ^ 0x6c7967656e657261; + uint64_t v3 = c ^ 0x7465646279746573; + uint64_t m; - uint8_t *message = (uint8_t *)key; - size_t remaining = key_length; uint64_t hash; - message += sizeof(uint64_t); - k1 = *(uint64_t *)message; + uint8_t *message = (uint8_t *)key; - if (key_length % sizeof(uint64_t) != 0) { - memcpy(&k1, key + (key_length - sizeof(uint64_t)), sizeof(uint64_t)); - } + size_t remaining = key_length; + size_t offset = 0; while (remaining >= 8) { - memcpy(&m, message, sizeof(uint64_t)); + memcpy(&m, message + offset, sizeof(uint64_t)); v3 ^= m; for (int i = 0; i < 2; i++) { - v0 += v1; - v2 += v3; + v0 = sip_round(v0, v1, v2, v3); v1 = ROTATE_LEFT(v1, 13); - v3 = ROTATE_LEFT(v3, 16); - v1 ^= v0; - v3 ^= v2; - v0 = ROTATE_LEFT(v0, 32); - v2 += v1; - v0 += v3; - v1 = ROTATE_LEFT(v1, 17); - v3 = ROTATE_LEFT(v3, 21); - v1 ^= v2; - v3 ^= v0; - v2 = ROTATE_LEFT(v2, 32); + v2 = ROTATE_LEFT(v2, 16); + v3 = ROTATE_LEFT(v3, 32); + v0 ^= m; } - v0 ^= m; + v2 ^= 0xff; + for (int i = 0; i < 4; i++) { + v0 = sip_round(v0, v1, v2, v3); + v1 = ROTATE_LEFT(v1, 13); + v2 = ROTATE_LEFT(v2, 16); + v3 = ROTATE_LEFT(v3, 32); + } + + hash = v0 ^ v1 ^ v2 ^ v3; remaining -= sizeof(uint64_t); - message += sizeof(uint64_t); + offset += sizeof(uint64_t); } m = (uint64_t)remaining << 56; - switch (remaining) { case 7: - m |= (uint64_t)message[6] << 48; + m |= (uint64_t)message[offset + 6] << 48; break; case 6: - m |= (uint64_t)message[5] << 40; + m |= (uint64_t)message[offset + 5] << 40; break; case 5: - m |= (uint64_t)message[4] << 32; + m |= (uint64_t)message[offset + 4] << 32; break; case 4: - m |= (uint64_t)message[3] << 24; + m |= (uint64_t)message[offset + 3] << 24; break; case 3: - m |= (uint64_t)message[2] << 16; + m |= (uint64_t)message[offset + 2] << 16; break; case 2: - m |= (uint64_t)message[1] << 8; + m |= (uint64_t)message[offset + 1] << 8; break; case 1: - m |= (uint64_t)message[0]; + m |= (uint64_t)message[offset]; break; default: break; @@ -79,40 +91,20 @@ uint64_t hash(string_t key, size_t capacity) { v3 ^= m; for (int i = 0; i < 2; i++) { - v0 += v1; - v2 += v3; + v0 = sip_round(v0, v1, v2, v3); v1 = ROTATE_LEFT(v1, 13); - v3 = ROTATE_LEFT(v3, 16); - v1 ^= v0; - v3 ^= v2; - v0 = ROTATE_LEFT(v0, 32); - v2 += v1; - v0 += v3; - v1 = ROTATE_LEFT(v1, 17); - v3 = ROTATE_LEFT(v3, 21); - v1 ^= v2; - v3 ^= v0; - v2 = ROTATE_LEFT(v2, 32); + v2 = ROTATE_LEFT(v2, 16); + v3 = ROTATE_LEFT(v3, 32); } v0 ^= m; v2 ^= 0xff; for (int i = 0; i < 4; i++) { - v0 += v1; - v2 += v3; + v0 = sip_round(v0, v1, v2, v3); v1 = ROTATE_LEFT(v1, 13); - v3 = ROTATE_LEFT(v3, 16); - v1 ^= v0; - v3 ^= v2; - v0 = ROTATE_LEFT(v0, 32); - v2 += v1; - v0 += v3; - v1 = ROTATE_LEFT(v1, 17); - v3 = ROTATE_LEFT(v3, 21); - v1 ^= v2; - v3 ^= v0; - v2 = ROTATE_LEFT(v2, 32); + v2 = ROTATE_LEFT(v2, 16); + v3 = ROTATE_LEFT(v3, 32); } hash = v0 ^ v1 ^ v2 ^ v3; diff --git a/lib/string.c b/lib/string.c index eb380be..16fba0a 100644 --- a/lib/string.c +++ b/lib/string.c @@ -92,8 +92,18 @@ string_t string_trim(string_t string_value) { return result; } -string_t string_copy(const string_t string_value) { - return string_substring(string_value, 0, string_get_length(string_value)); +string_t string_copy(const string_t source) { + size_t source_length = string_get_length(source); + string_t copy = malloc(sizeof(char) * (source_length + 1)); + if (copy == NULL) { + exit(EXIT_FAILURE); + } + size_t index; + for (index = 0; index < source_length; index++) { + copy[index] = source[index]; + } + copy[index] = '\0'; + return copy; } string_t string_capitalize(string_t string_value) { @@ -181,28 +191,34 @@ string_t* string_split(const string_t string_value, char separator, size_t* resu size_t index_current = 0; size_t index_result = 0; string_t current = malloc(sizeof(char) * (string_length + 1)); - string_t* result = malloc(sizeof(char*) * index_result); - if (result == NULL || current == NULL) { + string_t* result = NULL; + + if (current == NULL) { exit(EXIT_FAILURE); } + while (index_string < string_length) { if (string_value[index_string] == separator) { current[index_current] = '\0'; - result[index_result] = string_copy(current); - index_result++; - result = realloc(result, sizeof(string_value) * (index_result + 1)); + result = realloc(result, sizeof(string_t) * (index_result + 1)); if (result == NULL) { exit(EXIT_FAILURE); } - index_current = 0; - current = string_copy(""); + result[index_result] = string_copy(current); + index_result++; + index_current = 0; // Reset index_current for the next substring } else { current[index_current] = string_value[index_string]; index_current++; } index_string++; } + current[index_current] = '\0'; + result = realloc(result, sizeof(string_t) * (index_result + 1)); + if (result == NULL) { + exit(EXIT_FAILURE); + } result[index_result] = string_copy(current); free(current); *result_size = index_result + 1; @@ -210,27 +226,30 @@ string_t* string_split(const string_t string_value, char separator, size_t* resu } string_t string_join(string_t* array, const char separator, size_t array_length) { - size_t string_length = array_length; - string_t string_value = malloc(sizeof(string_value) * string_length); + size_t total_length = 0; + for (size_t index_array = 0; index_array < array_length; index_array++) { + total_length += string_get_length(array[index_array]); + } + size_t string_length = total_length + (array_length - 1); + string_t string_value = malloc(sizeof(char) * (string_length + 1)); if (string_value == NULL) { exit(EXIT_FAILURE); } + size_t current_index = 0; for (size_t index_array = 0; index_array < array_length; index_array++) { string_t substring = array[index_array]; size_t substring_length = string_get_length(substring); - string_length += substring_length; - string_value = realloc(string_value, sizeof(string_value) * string_length); - if (string_value == NULL) { - exit(EXIT_FAILURE); - } for (size_t index_substring = 0; index_substring < substring_length; index_substring++) { - character_append(string_value, substring[index_substring]); + string_value[current_index] = substring[index_substring]; + current_index++; } bool is_last_character = index_array == (array_length - 1); if (!is_last_character) { - character_append(string_value, separator); + string_value[current_index] = separator; + current_index++; } } + string_value[string_length] = '\0'; return string_value; } @@ -270,11 +289,12 @@ bool string_get_has_unique_characters(const string_t string_value) { } string_t string_substring(const string_t string_value, size_t index_start, size_t index_end) { - size_t string_length = string_get_length(string_value); - string_t result = malloc(sizeof(char) * (string_length + 1)); - for (size_t index = index_start; index <= index_end; index++) { - character_append(result, string_value[index]); + size_t substring_length = index_end - index_start + 1; + string_t result = malloc(sizeof(char) * (substring_length + 1)); + for (size_t index = 0; index < substring_length; index++) { + result[index] = string_value[index_start + index]; } + result[substring_length] = '\0'; return result; } @@ -301,25 +321,28 @@ string_t string_get_formatted_number(const long long number, string_t separator) number_string = string_substring(number_string, 1, string_get_length(number_string)); } size_t number_string_length = string_get_length(number_string); - string_t result = malloc(sizeof(char) * (number_string_length + 1)); + size_t formatted_length = number_string_length + (number_string_length - 1) / 3; + string_t result = malloc(sizeof(char) * (formatted_length + 1)); if (result == NULL) { exit(EXIT_FAILURE); } size_t count = 0; + size_t result_index = 0; for (size_t index = 0; index < number_string_length; index++) { size_t index_reversed = number_string_length - index - 1; + result[result_index] = number_string[index_reversed]; count++; - result = string_concatenate(result, convert_character_to_string(number_string[index_reversed])); - if (count == 3) { - result = string_concatenate(result, separator); + result_index++; + if (count == 3 && index != number_string_length - 1) { + for (size_t sep_index = 0; sep_index < string_get_length(separator); sep_index++) { + result[result_index] = separator[sep_index]; + result_index++; + } count = 0; } } + result[formatted_length] = '\0'; result = string_reverse(result); - size_t result_length = string_get_length(result); - if (result_length % 4 == 0) { - result = string_substring(result, 1, result_length); - } if (is_negative) { result = string_concatenate(convert_character_to_string('-'), result); } @@ -328,19 +351,24 @@ string_t string_get_formatted_number(const long long number, string_t separator) string_t string_get_last_occurence_of_character(const string_t string_value, char character) { size_t string_length = string_get_length(string_value); - string_t result = malloc(sizeof(char) * (string_length + 1)); + size_t index_last_occurrence = SIZE_MAX; + for (size_t index = 0; index < string_length; index++) { + if (string_value[index] == character) { + index_last_occurrence = index; + } + } + if (index_last_occurrence == SIZE_MAX) { + return string_copy(""); + } + string_t result = malloc(sizeof(char) * (string_length - index_last_occurrence + 1)); if (result == NULL) { exit(EXIT_FAILURE); } size_t index_result = 0; - for (size_t index = 0; index < string_length; index++) { - if (string_value[index] == character) { - index_result = 0; - result = string_copy(""); - } - character_append(result, string_value[index]); - index_result++; + for (size_t index = index_last_occurrence; index < string_length; index++) { + result[index_result++] = string_value[index]; } + result[index_result] = '\0'; return result; } diff --git a/test/character_test.c b/test/character_test.c index 8c8749e..9ae1764 100644 --- a/test/character_test.c +++ b/test/character_test.c @@ -20,7 +20,7 @@ void character_append_at_test() { character_append_at(string, 'd', 1); assert(assert_string_equal(string, "adbc")); - char string2[5] = "abcd"; + char string2[6] = "abcd"; character_append_at(string2, 'e', 4); assert(assert_string_equal(string2, "abcde")); } diff --git a/test/string_test.c b/test/string_test.c index e0032c8..0e5ecf4 100644 --- a/test/string_test.c +++ b/test/string_test.c @@ -36,36 +36,42 @@ void string_to_uppercase_test() { string_t string = "heLlO world"; string = string_to_uppercase(string); assert(assert_string_equal(string, "HELLO WORLD")); + free(string); } void string_to_lowercase_test() { string_t string = "HellO WoRLd"; string = string_to_lowercase(string); assert(assert_string_equal(string, "hello world")); + free(string); } void string_replace_test() { string_t string = "hello world"; string = string_replace(string, 'l', 'z'); assert(assert_string_equal(string, "hezzo worzd")); + free(string); } void string_trim_start_test() { string_t string = " hello world "; string = string_trim_start(string); assert(assert_string_equal(string, "hello world ")); + free(string); } void string_trim_end_test() { string_t string = " hello world "; string = string_trim_end(string); assert(assert_string_equal(string, " hello world")); + free(string); } void string_trim_test() { string_t string = " hello world "; string = string_trim(string); assert(assert_string_equal(string, "hello world")); + free(string); } void string_copy_test() { @@ -76,12 +82,14 @@ void string_copy_test() { assert(assert_string_not_equal(string, string2)); assert(assert_string_equal(string, "hello world")); assert(assert_string_equal(string2, "aello world")); + free(string2); } void string_capitalize_test() { string_t string = "hello world"; string = string_capitalize(string); assert(assert_string_equal(string, "Hello world")); + free(string); } void string_total_occurrences_of_character_test() { @@ -93,6 +101,7 @@ void string_reverse_test() { string_t string = "hello world"; string = string_reverse(string); assert(assert_string_equal(string, "dlrow olleh")); + free(string); } void string_equals_test() { @@ -125,6 +134,10 @@ void string_split_test() { assert(assert_string_equal(result[1], "def")); assert(assert_string_equal(result[2], "ghij")); assert(assert_string_equal(result[3], "kl")); + for (size_t index = 0; index < result_length; index++) { + free(result[index]); + } + free(result); } void string_join_test() { @@ -135,11 +148,22 @@ void string_join_test() { string_t new_string2 = string_join(result, '+', result_length); assert(assert_string_equal(new_string, string)); assert(assert_string_equal(new_string2, "abc+def+ghij+kl")); + free(new_string); + free(new_string2); + for (size_t index = 0; index < result_length; index++) { + free(result[index]); + } + free(result); } void string_concatenate_test() { - assert(assert_string_equal(string_concatenate("abc", "def"), "abcdef")); - assert(assert_string_equal(string_concatenate("abc ", " defghi"), "abc defghi")); + char* result = string_concatenate("abc", "def"); + assert(assert_string_equal(result, "abcdef")); + free(result); + + result = string_concatenate("abc", " defghi"); + assert(assert_string_equal(result, "abc defghi")); + free(result); } void string_get_has_unique_characters_test() { @@ -152,6 +176,7 @@ void string_substring_test() { string_t string = "abcdef"; string_t substring = string_substring(string, 1, 3); assert(assert_string_equal(substring, "bcd")); + free(substring); } void string_get_is_substring_test() { @@ -167,33 +192,61 @@ void string_get_is_substring_test() { } void string_get_formatted_number_test() { - assert(assert_string_equal(string_get_formatted_number(1000, " "), "1 000")); - assert(assert_string_equal(string_get_formatted_number(123, ","), "123")); - assert(assert_string_equal(string_get_formatted_number(1234, ","), "1,234")); - assert(assert_string_equal(string_get_formatted_number(12345, ","), "12,345")); - assert(assert_string_equal(string_get_formatted_number(123456, ","), "123,456")); - assert(assert_string_equal(string_get_formatted_number(1234567, ","), "1,234,567")); - assert(assert_string_equal(string_get_formatted_number(12345678, ","), "12,345,678")); - assert(assert_string_equal(string_get_formatted_number(123456789, ","), "123,456,789")); - assert(assert_string_equal(string_get_formatted_number(1234567890, ","), "1,234,567,890")); - assert(assert_string_equal(string_get_formatted_number(-123, ","), "-123")); - assert(assert_string_equal(string_get_formatted_number(-1234, ","), "-1,234")); - assert(assert_string_equal(string_get_formatted_number(-12345, ","), "-12,345")); - assert(assert_string_equal(string_get_formatted_number(-123456, ","), "-123,456")); - assert(assert_string_equal(string_get_formatted_number(-1234567, ","), "-1,234,567")); - assert(assert_string_equal(string_get_formatted_number(-12345678, ","), "-12,345,678")); - assert(assert_string_equal(string_get_formatted_number(-123456789, ","), "-123,456,789")); - assert(assert_string_equal(string_get_formatted_number(-1234567890, ","), "-1,234,567,890")); + char* result = string_get_formatted_number(1000, " "); + assert(assert_string_equal(result, "1 000")); + free(result); + + result = string_get_formatted_number(123, ","); + assert(assert_string_equal(result, "123")); + free(result); + + result = string_get_formatted_number(1234, ","); + assert(assert_string_equal(result, "1,234")); + free(result); + + result = string_get_formatted_number(12345, ","); + assert(assert_string_equal(result, "12,345")); + free(result); + + result = string_get_formatted_number(-123, ","); + assert(assert_string_equal(result, "-123")); + free(result); + + result = string_get_formatted_number(-1234, ","); + assert(assert_string_equal(result, "-1,234")); + free(result); + + result = string_get_formatted_number(-1234567890, ","); + assert(assert_string_equal(result, "-1,234,567,890")); + free(result); } void string_get_last_occurence_of_character_test() { string_t string = "abcdef"; - assert(assert_string_equal(string_get_last_occurence_of_character(string, 'a'), "abcdef")); - assert(assert_string_equal(string_get_last_occurence_of_character(string, 'b'), "bcdef")); - assert(assert_string_equal(string_get_last_occurence_of_character(string, 'c'), "cdef")); - assert(assert_string_equal(string_get_last_occurence_of_character(string, 'd'), "def")); - assert(assert_string_equal(string_get_last_occurence_of_character(string, 'e'), "ef")); - assert(assert_string_equal(string_get_last_occurence_of_character(string, 'f'), "f")); + + char *result = string_get_last_occurence_of_character(string, 'a'); + assert(assert_string_equal(result, "abcdef")); + free(result); + + result = string_get_last_occurence_of_character(string, 'b'); + assert(assert_string_equal(result, "bcdef")); + free(result); + + result = string_get_last_occurence_of_character(string, 'c'); + assert(assert_string_equal(result, "cdef")); + free(result); + + result = string_get_last_occurence_of_character(string, 'd'); + assert(assert_string_equal(result, "def")); + free(result); + + result = string_get_last_occurence_of_character(string, 'e'); + assert(assert_string_equal(result, "ef")); + free(result); + + result = string_get_last_occurence_of_character(string, 'f'); + assert(assert_string_equal(result, "f")); + free(result); } void string_starts_with_test() {