diff --git a/CMakeLists.txt b/CMakeLists.txt index 06d6e57..618a587 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,10 @@ cmake_minimum_required(VERSION 3.26) +set(CMAKE_C_STANDARD 90) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -17,7 +21,7 @@ set( project( ForFun - LANGUAGES CXX + LANGUAGES C CXX ) add_library( @@ -45,6 +49,21 @@ target_include_directories( link_libraries(forfun) +add_library( + forfun_c + SHARED + "include/forfun/palindrome.h" + "src/palindrome.c" +) + +target_include_directories( + forfun_c + PUBLIC + "${CMAKE_SOURCE_DIR}/include" +) + +link_libraries(forfun_c) + add_executable( fizzbuzz "test/fizzbuzz.cpp" @@ -60,6 +79,11 @@ add_executable( "test/palindrome.cpp" ) +add_executable( + palindrome_c + "test/palindrome.c" +) + add_executable( palindromic_number "test/palindromic_number.cpp" diff --git a/README.md b/README.md index 607420e..14fadb9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Miscellaneous coding problem solutions -Solutions written in C++ (C++17 and C++20) for various coding problems. +Solutions for various coding problems, written in C90, C++17, and C++20. The solutions are not necessarily optimal or meant as best practice. diff --git a/benchmark/palindrome_benchmark.cpp b/benchmark/palindrome_benchmark.cpp index de89a2b..5689dae 100644 --- a/benchmark/palindrome_benchmark.cpp +++ b/benchmark/palindrome_benchmark.cpp @@ -12,6 +12,7 @@ #include +#include "forfun/palindrome.h" #include "forfun/palindrome.hpp" TEST_CASE("forfun::palindrome benchmarking") { @@ -24,6 +25,14 @@ TEST_CASE("forfun::palindrome benchmarking") { .title("Palindrome (case-sensitive)") + .run( + NAMEOF_RAW(::is_palindrome).c_str(), + [&palindrome]() { + auto r{ + ::is_palindrome(palindrome.data(), palindrome.size())}; + ankerl::nanobench::doNotOptimizeAway(r); + }) + .run( NAMEOF_RAW(forfun::palindrome::fast::is_palindrome).c_str(), [&palindrome]() { @@ -63,6 +72,14 @@ TEST_CASE("forfun::palindrome benchmarking") { .title("Palindrome (case-insensitive)") + .run( + NAMEOF_RAW(::is_palindrome_ci).c_str(), + [&palindrome]() { + auto r{::is_palindrome_ci( + palindrome.data(), palindrome.size())}; + ankerl::nanobench::doNotOptimizeAway(r); + }) + .run( NAMEOF_RAW(forfun::palindrome::fast::is_palindrome_ci).c_str(), [&palindrome]() { diff --git a/include/forfun/palindrome.h b/include/forfun/palindrome.h new file mode 100644 index 0000000..4beb194 --- /dev/null +++ b/include/forfun/palindrome.h @@ -0,0 +1,31 @@ +/* +Copyright (c) Omar Boukli-Hacene. All rights reserved. +Distributed under an MIT-style license that can be +found in the LICENSE file. +*/ + +/* SPDX-License-Identifier: MIT */ + +/* +Problem reference: +https://en.wikipedia.org/wiki/Palindrome +*/ + +#ifndef FORFUN_PALINDROME_H_ +#define FORFUN_PALINDROME_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +int is_palindrome(char const* const str, size_t const size); + +int is_palindrome_ci(char const* const str, size_t const size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* FORFUN_PALINDROME_H_ */ diff --git a/src/palindrome.c b/src/palindrome.c new file mode 100644 index 0000000..68a09f8 --- /dev/null +++ b/src/palindrome.c @@ -0,0 +1,40 @@ +/* +Copyright (c) Omar Boukli-Hacene. All rights reserved. +Distributed under an MIT-style license that can be +found in the LICENSE file. +*/ + +/* SPDX-License-Identifier: MIT */ + +#include "forfun/palindrome.h" + +#include + +int is_palindrome(char const* const str, size_t const size) { + size_t const end = size - 1; + size_t const mid = size / 2; + + size_t i; + for (i = 0; i < mid; ++i) { + if (str[i] != str[end - i]) { + return 0; + } + } + + return 1; +} + +int is_palindrome_ci(char const* const str, size_t const size) { + size_t const end = size - 1; + size_t const mid = size / 2; + + size_t i; + for (i = 0; i < mid; ++i) { + if (tolower((unsigned char)str[i]) + != tolower((unsigned char)str[end - i])) { + return 0; + } + } + + return 1; +} diff --git a/test/palindrome.c b/test/palindrome.c new file mode 100644 index 0000000..a73d461 --- /dev/null +++ b/test/palindrome.c @@ -0,0 +1,94 @@ +/* +Copyright (c) Omar Boukli-Hacene. All rights reserved. +Distributed under an MIT-style license that can be +found in the LICENSE file. +*/ + +/* SPDX-License-Identifier: MIT */ + +#include "forfun/palindrome.h" + +#include +#include + +void test_palindrome() { + { + char const* const s = ""; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "\xb8Y\xb8"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "aa"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "aba"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "a b a"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "101"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "tattarrattat"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome); + } + + { + char const* const s = "dummy"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome(s, len); + assert(f_palindrome == 0); + } +} + +void test_palindrome_ci() { + { + char const* const s = "Aa"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome_ci(s, len); + assert(f_palindrome); + } + + { + char const* const s = "Aab4'{x{'4BaA"; + size_t const len = strlen(s); + int const f_palindrome = is_palindrome_ci(s, len); + assert(f_palindrome); + } +} + +int main() { + test_palindrome(); + + test_palindrome_ci(); + + return 0; +}