diff --git a/coresdk/src/coresdk/basics.cpp b/coresdk/src/coresdk/basics.cpp index 7fe72bf5..479b224c 100644 --- a/coresdk/src/coresdk/basics.cpp +++ b/coresdk/src/coresdk/basics.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include +#include #include #include @@ -78,7 +81,10 @@ namespace splashkit_lib { size_t pos = text.find(subtext); if (pos == string::npos) + { return -1; + } + return static_cast(pos); } @@ -99,21 +105,26 @@ namespace splashkit_lib vector split(const string &text, char delimiter) { - vector result; - string::size_type start = 0; - string::size_type end = text.find(delimiter); - while (end != string::npos) + // To check to keep the same functionality required on line 523 of unit_test_utilities.cpp + // Will return an empty vector without this check + if (text.empty()) + { + return vector{ text }; + } + + vector result{}; + for(const auto& strings : std::views::split(text, delimiter)) { - result.push_back(text.substr(start, end - start)); - start = end + 1; - end = text.find(delimiter, start); + result.emplace_back(strings.begin(), strings.end()); } - result.push_back(text.substr(start)); + return result; + // To future maintainers: if the codebase gets upgraded to C++23 or newer, + // remove the above code and uncomment the code bellow + // return text | std::views::split(delimiter) | std::ranges::to>(); } // integer check see: https://stackoverflow.com/questions/2844817/how-do-i-check-if-a-c-string-is-an-int#2845275 - bool is_integer(const string &text) { string s = trim(text); @@ -153,49 +164,44 @@ namespace splashkit_lib return std::stod(text); } + bool is_valid_input(std::string_view input, std::string_view valid_characters) + { + return input.find_first_not_of(valid_characters) == std::string_view::npos; + } + bool is_binary(const string &bin_str) { - for (char c : bin_str) + if (bin_str.empty()) { - if (c != '0' && c != '1') - return false; + return false; } - return !bin_str.empty(); + + return is_valid_input(bin_str, "01"); } bool is_hex(const string &hex_str) { - for (char c : hex_str) + if (hex_str.empty()) { - if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) - return false; + return false; } - return !hex_str.empty(); + + return is_valid_input(hex_str, "0123456789aAbBcCdDeEfF"); } bool is_octal(const string &octal_str) { - for (char c : octal_str) + if (octal_str.empty()) { - if (c < '0' || c > '7') - return false; + return false; } - return !octal_str.empty(); + + return is_valid_input(octal_str, "01234567"); } string dec_to_bin(unsigned int a_dec) { - // Without this check, dec to bin will not work if dec is 0 - if (a_dec == 0) - return "0"; - - string bin_string; - while (a_dec > 0) - { - bin_string = ((a_dec & 1) ? "1" : "0") + bin_string; - a_dec >>= 1; - } - return bin_string; + return std::format("{:b}", a_dec); } unsigned int bin_to_dec(const string &bin_str) @@ -278,18 +284,7 @@ namespace splashkit_lib string dec_to_oct(unsigned int decimal_value) { - if (decimal_value == 0) - { - return "0"; - } - - string octal_string; - while (decimal_value > 0) - { - octal_string = std::to_string(decimal_value % 8) + octal_string; - decimal_value /= 8; - } - return octal_string; + return std::format("{:o}", decimal_value); } unsigned int oct_to_dec(const string &octal_string) @@ -322,20 +317,7 @@ namespace splashkit_lib return ""; } - string bin_string; - for (char oct_char : octal_str) - { - int oct_val = oct_char - '0'; - - // Convert each octal digit to a 3-bit binary representation - for (int i = 2; i >= 0; i--) - { - bin_string += ((oct_val >> i) & 1) ? '1' : '0'; - } - } - - size_t first_one = bin_string.find_first_not_of('0'); - return (first_one == string::npos) ? "0" : bin_string.substr(first_one); + return dec_to_bin(oct_to_dec(octal_str)); } string bin_to_oct(const string &bin_str) @@ -346,27 +328,7 @@ namespace splashkit_lib return ""; } - string octal_string; - - // Pad binary string with leading zeros to make its length a multiple of 3 - int padding = (3 - (bin_str.length() % 3)) % 3; - string padded_bin_str = string(padding, '0') + bin_str; - - for (size_t i = 0; i < padded_bin_str.length(); i += 3) - { - int oct_val = 0; - for (size_t j = 0; j < 3; j++) - { - oct_val <<= 1; - if (padded_bin_str[i + j] == '1') - oct_val |= 1; - } - - octal_string += '0' + oct_val; - } - - size_t first_non_zero = octal_string.find_first_not_of('0'); - return (first_non_zero == string::npos) ? "0" : octal_string.substr(first_non_zero); + return dec_to_oct(bin_to_dec(bin_str)); } string hex_to_oct(const string &hex_str) @@ -377,8 +339,7 @@ namespace splashkit_lib return ""; } - string bin_str = hex_to_bin(hex_str); - return bin_to_oct(bin_str); + return bin_to_oct(hex_to_bin(hex_str)); } string oct_to_hex(const string &octal_str) @@ -389,8 +350,7 @@ namespace splashkit_lib return ""; } - string bin_str = oct_to_bin(octal_str); - return bin_to_hex(bin_str); + return bin_to_hex(oct_to_bin(octal_str)); } string base64_encode(const string &input) @@ -496,4 +456,4 @@ namespace splashkit_lib return abs(number1 * number2) / greatest_common_divisor(number1, number2); } -} \ No newline at end of file +} diff --git a/coresdk/src/test/unit_tests/unit_test_utilities.cpp b/coresdk/src/test/unit_tests/unit_test_utilities.cpp index d2b871af..2e3ba08d 100644 --- a/coresdk/src/test/unit_tests/unit_test_utilities.cpp +++ b/coresdk/src/test/unit_tests/unit_test_utilities.cpp @@ -334,6 +334,14 @@ TEST_CASE("verify that string is double", "[is_double]") } TEST_CASE("verify that string is integer", "[is_integer]") { + SECTION("Edge Cases") + { + REQUIRE_FALSE(is_integer("1+2")); + REQUIRE_FALSE(is_integer("+-2")); + REQUIRE_FALSE(is_integer("--5")); + REQUIRE_FALSE(is_integer("5--")); + REQUIRE_FALSE(is_integer("5-")); + } SECTION("string is an integer") { REQUIRE(is_integer("123")); @@ -393,6 +401,12 @@ TEST_CASE("verify that string is integer", "[is_integer]") } TEST_CASE("verify that string is number", "[is_number]") { + SECTION("Edge Cases") + { + REQUIRE_FALSE(is_number("1.2.3")); + REQUIRE_FALSE(is_number("1.+2")); + REQUIRE_FALSE(is_number("1.-2")); + } SECTION("string is a double") { REQUIRE(is_number("123.456")); @@ -717,7 +731,7 @@ TEST_CASE("gets the number of milliseconds that have passed since the program wa TEST_CASE("program is put to sleep for a specified number of milliseconds", "[delay]") { constexpr long long DELAY_THRESHOLD = 80; - + SECTION("milliseconds is 0") { auto start = std::chrono::steady_clock::now(); @@ -747,7 +761,7 @@ TEST_CASE("return a SplashKit resource of resource_kind with name filename as a { const resource_kind RESOURCE = resource_kind::BUNDLE_RESOURCE; const string RESOURCE_PATH = "blah.txt"; - + SECTION("filename is a valid file") { string result = file_as_string(RESOURCE_PATH, RESOURCE); @@ -1017,4 +1031,4 @@ TEST_CASE("calculates the lcm of two numbers", "[least_common_multiple]") { REQUIRE(least_common_multiple(42, 42) == 42); } -} \ No newline at end of file +}