From bb85bd03bb0302bc9ae455c676862073efe4b44c Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Fri, 17 Apr 2026 09:37:04 +0700 Subject: [PATCH 1/6] Add example for type traits --- src/core/CMakeLists.txt | 1 + src/core/utils/TypeTrait.cpp | 119 +++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 src/core/utils/TypeTrait.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0ffa591..db6af89 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -99,6 +99,7 @@ set(CORE_SOURCES # Utils ${CMAKE_CURRENT_SOURCE_DIR}/utils/StdAlgorithm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/TypeTrait.cpp ) # Export CORE_SOURCES to the parent CMakeLists.txt diff --git a/src/core/utils/TypeTrait.cpp b/src/core/utils/TypeTrait.cpp new file mode 100644 index 0000000..aaeefd9 --- /dev/null +++ b/src/core/utils/TypeTrait.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +#ifdef __GNUG__ +#include +#endif + +#include +#include "ExampleRegistry.h" +#include "Logger.h" + +namespace type_trait { + +// Utility: readable type name +template +std::string type_name() { +#ifdef __GNUG__ + int status = 0; + std::unique_ptr demangled( + abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status), + std::free); + return (status == 0 && demangled) ? demangled.get() : typeid(T).name(); +#else + return typeid(T).name(); +#endif +} + +// Trait: has operator &= +template +struct HaveAndAssign : std::false_type {}; + +template +struct HaveAndAssign< + T, std::void_t() &= std::declval())>> + : std::true_type {}; + +// Trait: has operator ! +template +struct HaveNot : std::false_type {}; + +template +struct HaveNot())>> : std::true_type { +}; + +// Example class WITH &= +template +class A { + public: + A& operator&=(const A&) { return *this; } +}; + +// Example class WITHOUT &= +template +class B {}; + +// Constrained class +template ::value, int> = 0> +class C { + public: + C() { + std::ostringstream oss; + oss << "C<" << type_name() << "> instantiated"; + LOG(oss.str()); + } +}; + +// Debug printer +template +void printTypeInfo() { + std::ostringstream oss; + oss << "==== Type Info ====\n" + << "Type: " << type_name() << '\n' + << "is_bool: " << std::is_same_v << '\n' + << "HaveAndAssign: " << HaveAndAssign::value << '\n' + << "HaveNot (!): " << HaveNot::value; + LOG(oss.str()); + LOG("==================="); +} + +void run() { + LOG("===== Type Traits Examples ====="); + + printTypeInfo(); + printTypeInfo>(); + printTypeInfo>(); + + if constexpr (HaveAndAssign>::value) { + LOG("A supports &="); + C> c_instance; + } else { + LOG("B does NOT support &="); + } + + if constexpr (HaveAndAssign>::value) { + LOG("B supports &="); + } else { + LOG("B does NOT support &="); + } + LOG("================================"); +} + +} // namespace type_trait + +class TypeTrait : public IExample { + public: + std::string group() const override { return "core/utils"; } + + std::string name() const override { return "TypeTrait"; } + + std::string description() const override { + return "Examples for with improved logging and SFINAE checks"; + } + + void execute() override { type_trait::run(); } +}; + +REGISTER_EXAMPLE(TypeTrait, "core/utils", "TypeTrait"); \ No newline at end of file From b4e1d6ad8f6e477ee9ea594c7dde824ae98dc7c0 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Apr 2026 10:50:15 +0700 Subject: [PATCH 2/6] Refactor --- scripts/gen_coverage_gcovr.sh | 12 ------------ src/CMakeLists.txt | 3 --- 2 files changed, 15 deletions(-) diff --git a/scripts/gen_coverage_gcovr.sh b/scripts/gen_coverage_gcovr.sh index 6fda7ab..fa27732 100755 --- a/scripts/gen_coverage_gcovr.sh +++ b/scripts/gen_coverage_gcovr.sh @@ -1,37 +1,27 @@ #!/usr/bin/env bash set -e -# ----------------------------------------------------------------------------- # Check gcovr installation -# ----------------------------------------------------------------------------- if ! command -v gcovr >/dev/null 2>&1; then echo "Error: gcovr is not installed." echo "Install with: pip install gcovr or sudo apt install gcovr or sudo apt install python3-gcovr" exit 1 fi -# ----------------------------------------------------------------------------- # Configure project (only if build folder does not exist) -# ----------------------------------------------------------------------------- if [ ! -d build ]; then cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="--coverage -O0 -g" fi -# ----------------------------------------------------------------------------- # Build project -# ----------------------------------------------------------------------------- cmake --build build -# ----------------------------------------------------------------------------- # Run unit tests -# ----------------------------------------------------------------------------- ctest --test-dir build --output-on-failure -# ----------------------------------------------------------------------------- # Generate coverage report -# ----------------------------------------------------------------------------- mkdir -p coverage_gcovr gcovr -r . build \ @@ -40,7 +30,5 @@ gcovr -r . build \ --html-details \ -o coverage_gcovr/index.html -# ----------------------------------------------------------------------------- # Open coverage report -# ----------------------------------------------------------------------------- xdg-open coverage_gcovr/index.html \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 189c463..00a3998 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,9 +30,6 @@ add_executable(${PROJECT_NAME} ) # Add header include paths -# PRIVATE -> this target only -# PUBLIC -> this target + dependent targets -# INTERFACE -> dependent targets only target_include_directories(${PROJECT_NAME} PRIVATE ${APP_HEADERS} ) From 3a6573ab0513e4796b54654875ea118118dd7150 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Apr 2026 11:44:26 +0700 Subject: [PATCH 3/6] Integrate AppMode --- src/main.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1752b42..b1b0512 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ +#include #include #include #include +#include #include #include "ExampleRegistry.h" @@ -34,8 +36,9 @@ void runMenu() { } // Group - int gIndex = 1; + size_t g_index = 1; std::vector groups; + groups.reserve(data.size()); for (const auto& [group, _] : data) { groups.push_back(group); @@ -44,50 +47,50 @@ void runMenu() { // sort std::sort(groups.begin(), groups.end()); for (const auto& group : groups) { - std::cout << gIndex++ << ". " << group << "\n"; + std::cout << g_index++ << ". " << group << "\n"; } - std::cout << gIndex << ". Exit\n"; + std::cout << g_index << ". Exit\n"; std::cout << "----------------------------------------\n"; std::cout << "Enter choice: "; - int gChoice = readChoice(); - if (gChoice == gIndex) { + size_t g_choice = readChoice(); + if (g_choice == g_index) { std::cout << "\n--- Exit ---\n"; break; } - if (gChoice < 1 || gChoice > groups.size()) { + if (g_choice < 1 || g_choice > groups.size()) { std::cout << "Invalid group choice\n"; continue; } try { // Sub-group - const auto& selectedGroup = groups[gChoice - 1]; - const auto& examples = data.at(selectedGroup); + const auto& selected_group = groups[g_choice - 1]; + const auto& examples = data.at(selected_group); - int eIndex = 1; + int e_index = 1; std::vector names; for (const auto& [name, _] : examples) { - std::cout << eIndex++ << ". " << name << "\n"; + std::cout << e_index++ << ". " << name << "\n"; names.push_back(name); } - std::cout << eIndex << ". Back\n"; + std::cout << e_index << ". Back\n"; std::cout << "----------------------------------------\n"; std::cout << "Enter choice: "; - int eChoice = readChoice(); - if (eChoice == eIndex) { + int e_choice = readChoice(); + if (e_choice == e_index) { continue; } - if (eChoice < 1 || eChoice > eIndex) { + if (e_choice < 1 || e_choice > e_index) { std::cout << "Invalid example choice\n"; continue; } - auto example = registry.create(selectedGroup, names[eChoice - 1]); + auto example = registry.create(selected_group, names[e_choice - 1]); if (example != nullptr) { std::cout << "\n--- Running Example [" << example->name() << "] [" << example->description() << "]---\n\n"; @@ -103,8 +106,7 @@ void runMenu() { } } -int main(int argc, char* argv[]) { - LOG("Logger has been integrated"); +void printInfo() { std::cout << std::endl; if (__cplusplus == 202302L) std::cout << "C++23"; @@ -123,6 +125,69 @@ int main(int argc, char* argv[]) { std::cout << "\n"; std::cout << APP_NAME << " v" << APP_VERSION << std::endl; std::cout << APP_DESCRIPTION << std::endl; +} + +enum class ApplicationMode { + kDev, + kUAT, + kProd, +}; + +static ApplicationMode mode = ApplicationMode::kDev; + +std::string toString(ApplicationMode m) { + switch (m) { + case ApplicationMode::kDev: + return "dev"; + case ApplicationMode::kUAT: + return "uat"; + case ApplicationMode::kProd: + return "prod"; + } + return "unknown"; +} + +ApplicationMode parseMode(const std::string& value) { + if (value == "Dev") + return ApplicationMode::kDev; + if (value == "Uat") + return ApplicationMode::kUAT; + if (value == "Prod") + return ApplicationMode::kProd; + + throw std::invalid_argument("Invalid mode: " + value + + ". Expected: dev, uat, prod"); +} + +void handleArg(int argc, const char* const argv[]) { + // argv[0] = executable + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + + if (arg == "-mode") { + if (i + 1 >= argc) { + std::cerr << "Missing value for -mode\n"; + return; + } + + std::string value = argv[++i]; + try { + mode = parseMode(value); + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + } + } else { + std::cerr << "Invalid argv param: " << arg << "\n"; + } + } +} + +int main(int argc, char* argv[]) { + handleArg(argc, argv); + LOG("Running in mode: " + toString(mode)); + LOG("Logger has been integrated"); + printInfo(); runMenu(); + return 0; } \ No newline at end of file From de9460da8040ed3614f4774fba05d7112013fa29 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Apr 2026 12:14:57 +0700 Subject: [PATCH 4/6] Refactor --- scripts/gen_coverage_lcov.sh | 16 ---- src/core/basics/ControlFlow.cpp | 57 ++++++------ src/core/basics/InitializeVariable.cpp | 44 ++++++---- src/core/basics/Operations.cpp | 116 ++++++++++++------------- src/core/basics/README.md | 7 +- 5 files changed, 112 insertions(+), 128 deletions(-) diff --git a/scripts/gen_coverage_lcov.sh b/scripts/gen_coverage_lcov.sh index 64732d3..5197272 100755 --- a/scripts/gen_coverage_lcov.sh +++ b/scripts/gen_coverage_lcov.sh @@ -1,42 +1,30 @@ #!/usr/bin/env bash set -e -# ----------------------------------------------------------------------------- # Check lcov installation -# ----------------------------------------------------------------------------- if ! command -v lcov >/dev/null 2>&1; then echo "Error: lcov is not installed." echo "Install with: sudo apt install lcov" exit 1 fi -# ----------------------------------------------------------------------------- # Configure project (only if build folder does not exist) -# ----------------------------------------------------------------------------- if [ ! -d build ]; then cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="--coverage -O0 -g" fi -# ----------------------------------------------------------------------------- # Build project -# ----------------------------------------------------------------------------- cmake --build build -# ----------------------------------------------------------------------------- # Reset previous coverage -# ----------------------------------------------------------------------------- lcov --directory build --zerocounters -# ----------------------------------------------------------------------------- # Run unit tests -# ----------------------------------------------------------------------------- ctest --test-dir build --output-on-failure -# ----------------------------------------------------------------------------- # Capture coverage -# ----------------------------------------------------------------------------- mkdir -p coverage_lcov lcov --capture \ @@ -49,13 +37,9 @@ lcov --capture \ lcov --remove coverage_lcov/coverage.info '/usr/*' \ --output-file coverage_lcov/coverage.info -# ----------------------------------------------------------------------------- # Generate HTML report -# ----------------------------------------------------------------------------- genhtml coverage_lcov/coverage.info \ --output-directory coverage_lcov -# ----------------------------------------------------------------------------- # Open coverage report -# ----------------------------------------------------------------------------- xdg-open coverage_lcov/index.html \ No newline at end of file diff --git a/src/core/basics/ControlFlow.cpp b/src/core/basics/ControlFlow.cpp index 25c2b05..4da1b50 100644 --- a/src/core/basics/ControlFlow.cpp +++ b/src/core/basics/ControlFlow.cpp @@ -1,47 +1,47 @@ #include -#include -using namespace std; +#include "ExampleRegistry.h" +namespace { void conditionals() { - cout << "\n--- Conditional Examples ---\n"; + std::cout << "\n--- Conditional Examples ---\n"; // if-else int x = rand(); - cout << "x = " << x << "\n"; + std::cout << "x = " << x << "\n"; if (x > 0) { - cout << "x is positive\n"; + std::cout << "x is positive\n"; } else if (x < 0) { - cout << "x is negative\n"; + std::cout << "x is negative\n"; } else { - cout << "x is zero\n"; + std::cout << "x is zero\n"; } // switch int choice = rand() % 2 + 1; - cout << "choice = " << x << "\n"; + std::cout << "choice = " << x << "\n"; switch (choice) { case 1: - cout << "Choice is 1\n"; + std::cout << "Choice is 1\n"; break; case 2: - cout << "Choice is 2\n"; + std::cout << "Choice is 2\n"; break; default: - cout << "Choice is something else\n"; + std::cout << "Choice is something else\n"; break; } } void jumps() { - cout << "\n--- Jump Statement Examples ---\n"; + std::cout << "\n--- Jump Statement Examples ---\n"; // goto int num = rand(); if (num == 3) goto jumpLabel; - cout << "This line will be skipped.\n"; + std::cout << "This line will be skipped.\n"; jumpLabel: - cout << "Jumped here using goto!\n"; + std::cout << "Jumped here using goto!\n"; // break / continue for (int i = 0; i < 5; ++i) { @@ -49,7 +49,7 @@ void jumps() { continue; // skip 2 if (i == 4) break; // stop loop at 4 - cout << "i = " << i << "\n"; + std::cout << "i = " << i << "\n"; } } @@ -59,43 +59,43 @@ int square(int n) { } void functionCalls() { - cout << "\n--- Function Call Examples ---\n"; + std::cout << "\n--- Function Call Examples ---\n"; // function call int result = square(5); - cout << "square(5) = " << result << "\n"; + std::cout << "square(5) = " << result << "\n"; } void loops() { - cout << "\n--- Loop Examples ---\n"; + std::cout << "\n--- Loop Examples ---\n"; // while int i = 0; while (i < 3) { - cout << "while loop i = " << i << "\n"; + std::cout << "while loop i = " << i << "\n"; ++i; } // do-while int j = 0; do { - cout << "do-while loop j = " << j << "\n"; + std::cout << "do-while loop j = " << j << "\n"; ++j; } while (j < 2); // for(initialization; condition; update) for (int k = 0; k < 3; ++k) { - cout << "for loop k = " << k << "\n"; + std::cout << "for loop k = " << k << "\n"; } // ranged-for const int arr[] = {10, 20, 30}; for (int value : arr) { - cout << "ranged-for value = " << value << "\n"; + std::cout << "ranged-for value = " << value << "\n"; } } void halts() { - cout << "\n--- Halt Examples ---\n"; + std::cout << "\n--- Halt Examples ---\n"; // std::exit() — terminates the program normally // std::abort() — terminates abnormally (no cleanup) @@ -106,17 +106,16 @@ void halts() { } void exceptions() { - cout << "\n--- Exception Handling Examples ---\n"; + std::cout << "\n--- Exception Handling Examples ---\n"; // try - catch - throw try { - throw runtime_error("Something went wrong!"); - } catch (const exception& e) { - cout << "Caught exception: " << e.what() << "\n"; + throw std::runtime_error("Something went wrong!"); + } catch (const std::exception& e) { + std::cout << "Caught exception: " << e.what() << "\n"; } } - -#include "ExampleRegistry.h" +} // namespace class ControlFlow : public IExample { public: diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp index c10602d..ad9b678 100644 --- a/src/core/basics/InitializeVariable.cpp +++ b/src/core/basics/InitializeVariable.cpp @@ -1,5 +1,5 @@ +// cppcheck-suppress-file [unreadVariable, unusedVariable, functionStatic] #include -using namespace std; #include "ExampleRegistry.h" @@ -16,48 +16,54 @@ class InitializeVariable : public IExample { REGISTER_EXAMPLE(InitializeVariable, "core", "InitializeVariable"); struct Foo { - Foo() { cout << "Default constructor/ default init\n"; } + Foo() { std::cout << "Default constructor/ default init\n"; } // Foo(int) - explicit Foo(int) { cout << "Constructor called with int / copy init\n"; } + explicit Foo(int) { + std::cout << "Constructor called with int / copy init\n"; + } - Foo(const Foo& other) { std::cout << "Copy constructor called\n"; } + Foo(const Foo& other) { + other.dump(); + std::cout << "Copy constructor called\n"; + } + + void dump() const {} }; void initialize_variable() { - cout << "\n--- Variable Initialization Examples ---\n"; + std::cout << "\n--- Variable Initialization Examples ---\n"; // There are there common ways to intialize a variable // * 1) Default-initialization - [[maybe_unused]] int initDefaultVar; - [[maybe_unused]] Foo initDefaultObj; + int init_default_var; + Foo init_default_obj; - [[maybe_unused]] unsigned char* c = new unsigned char; + auto* c = new unsigned char; *c = 0xF; // actual init at this point for c delete c; // * 2) Value-initialization - [[maybe_unused]] int initValueVar1(); - [[maybe_unused]] int initValueVar2{}; + int init_value_var1(); + int init_value_var2{}; // * 3) direct-init: Type var(value); - [[maybe_unused]] Foo directInitObj(4); // call Foo(int) - [[maybe_unused]] Foo directInitObj2( - 4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) -> + Foo direct_init_obj(4); // call Foo(int) + Foo direct_init_obj2(4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) // * 4) Copy-init: Type var = other; // 1. Compiler tries to convert the value to a temporary Foo. // 2. If the constructor is explicit, implicit conversion is blocked -> compilation error. // 3. Otherwise, a temporary Foo is created and then copied/moved into the variable. - [[maybe_unused]] Foo copyInitObj = - (Foo)2.3; // explicit cast: double 2.3 -> int 2 (implicit narrowing) -> Foo(int) - // -> temporary Foo -> copied/moved into copyInitObj + Foo copy_init_obj = (Foo)2.3; + // explicit cast: double 2.3 -> int 2 (implicit narrowing) -> Foo(int) + // -> temporary Foo -> copied/moved into copyInitObj // Foo copyInitObjError = 2.3; // ERROR: implicit conversion blocked by explicit constructor // We can explicitly prevent certain conversions using = delete or using {} // * 5) List-initialization (Brace init) // calls the constructor directly without allowing implicit conversions. - [[maybe_unused]] Foo braceInit{3}; + Foo brace_init{3}; // Foo braceInit2{3.3}; // ERORR => Prefer this way - [[maybe_unused]] int ar[] = {1, 2, 3}; // aggregate init - [[maybe_unused]] int ar2[]{1, 2, 3}; + int ar[] = {1, 2, 3}; // aggregate init + int ar2[]{1, 2, 3}; } \ No newline at end of file diff --git a/src/core/basics/Operations.cpp b/src/core/basics/Operations.cpp index e5f4575..1d618ac 100644 --- a/src/core/basics/Operations.cpp +++ b/src/core/basics/Operations.cpp @@ -1,5 +1,5 @@ #include -using namespace std; +#include #include "ExampleRegistry.h" @@ -22,107 +22,107 @@ class Operations : public IExample { REGISTER_EXAMPLE(Operations, "core", "Operations"); void arithmeticOperator() { - cout << "\n--- ArithmeticOperator Examples ---\n"; - int a{100}, b{200}; + std::cout << "\n--- ArithmeticOperator Examples ---\n"; + int a{100}; + int b{200}; // Addition - cout << "a = " << a << ", b = " << b << "\n"; + std::cout << "a = " << a << ", b = " << b << "\n"; int sum = a + b; - cout << "sum = " << sum << "\n"; + std::cout << "sum = " << sum << "\n"; // Subtraction - cout << "a = " << a << ", b = " << b << "\n"; + std::cout << "a = " << a << ", b = " << b << "\n"; int different = a - b; - cout << "different = " << different << "\n"; + std::cout << "different = " << different << "\n"; // Multiplication - cout << "a = " << a << ", b = " << b << "\n"; + std::cout << "a = " << a << ", b = " << b << "\n"; int product = a * b; - cout << "product = " << product << "\n"; + std::cout << "product = " << product << "\n"; // Division - cout << "a = " << a << ", b = " << b << "\n"; + std::cout << "a = " << a << ", b = " << b << "\n"; int quotient = a / b; - cout << "quotient = " << quotient << "\n"; + std::cout << "quotient = " << quotient << "\n"; // Modulus - cout << "a = " << a << ", b = " << b << "\n"; + std::cout << "a = " << a << ", b = " << b << "\n"; int remainder = a % b; - cout << "remainder = " << remainder << "\n"; + std::cout << "remainder = " << remainder << "\n"; // Increment - cout << "a = " << a << "\n"; - int preIn = ++a; // increase a, return a - cout << "preIn = " << preIn << "\n"; + std::cout << "a = " << a << "\n"; + int pre_in = ++a; // increase a, return a + std::cout << "preIn = " << pre_in << "\n"; - cout << "a = " << a << "\n"; - int postIn = a++; // copy a to a copy, then increase a, return copy - cout << "postIn = " << postIn << "\n"; + std::cout << "a = " << a << "\n"; + int post_in = a++; // copy a to a copy, then increase a, return copy + std::cout << "postIn = " << post_in << "\n"; // Decrement - cout << "b = " << b << "\n"; - int preDe = --b; - cout << "preDe = " << preDe << "\n"; + std::cout << "b = " << b << "\n"; + int pre_de = --b; + std::cout << "preDe = " << pre_de << "\n"; - cout << "b = " << b << "\n"; - int postDe = b--; - cout << "postDe = " << postDe << "\n"; + std::cout << "b = " << b << "\n"; + int post_de = b--; + std::cout << "postDe = " << post_de << "\n"; // Comma: int value = (a++, b); // a is incremented, then b is returned - cout << "a = " << a << ", b = " << b << "\n"; - cout << "comma(a++, b) = " << value << "\n"; + std::cout << "a = " << a << ", b = " << b << "\n"; + std::cout << "comma(a++, b) = " << value << "\n"; } void logicalOperator() { - cout << "\n--- LogicalOperator Examples ---\n"; + std::cout << "\n--- LogicalOperator Examples ---\n"; bool a = true; bool b = false; bool c = true; - cout << boolalpha; // show true/false instead of 1/0 - cout << "a = " << a << ", b = " << b << ", c = " << c << "\n\n"; + std::cout << std::boolalpha; // show true/false instead of 1/0 + std::cout << "a = " << a << ", b = " << b << ", c = " << c << "\n\n"; // AND (&&) - cout << "[AND] a && b = " << (a && b) << "\n"; + std::cout << "[AND] a && b = " << (a && b) << "\n"; // OR (||) - cout << "[OR ] a || b = " << (a || b) << "\n"; + std::cout << "[OR ] a || b = " << (a || b) << "\n"; // NOT (!) - cout << "[NOT] !c = " << (!c) << "\n"; + std::cout << "[NOT] !c = " << (!c) << "\n"; } -#include void bitWiseOperator() { - cout << "\n--- BitWiseOperator Examples ---\n"; - bitset<8> bitsA { - 0b1111'1111}; bitset<8> bitsB { 0b1111'0000}; + std::cout << "\n--- BitWiseOperator Examples ---\n"; + std::bitset<8> bits_a {0b1111'1111}; + std::bitset<8> bits_b {0b1111'0000}; - cout - << "bitA = " << bitsA << ", bitB = " << bitsB << "\n"; + std::cout + << "bitA = " << bits_a << ", bitB = " << bits_b << "\n"; - // AND - bitset<8> result = bitsA & bitsB; - cout << "bitA && bitB= " << result << "\n"; + // AND + std::bitset<8> result = bits_a & bits_b; + std::cout << "bitA && bitB= " << result << "\n"; - // OR - result = bitsA | bitsB; - cout << "bitA | bitB= " << result << "\n"; + // OR + result = bits_a | bits_b; + std::cout << "bitA | bitB= " << result << "\n"; - // XOR - result = bitsA ^ bitsB; - cout << "bitA ^ bitB= " << result << "\n"; + // XOR + result = bits_a ^ bits_b; + std::cout << "bitA ^ bitB= " << result << "\n"; - // NOT - result = ~bitsA; - cout << "~bitA = " << result << "\n"; + // NOT + result = ~bits_a; + std::cout << "~bitA = " << result << "\n"; - // LEFT SHIFT - result = bitsA << 1; - cout << "bitA << 1 = " << result << "\n"; + // LEFT SHIFT + result = bits_a << 1; + std::cout << "bitA << 1 = " << result << "\n"; - // RIGHT SHIFT - result = bitsA >> 1; - cout << "bitA >> 1 = " << result << "\n"; - } \ No newline at end of file + // RIGHT SHIFT + result = bits_a >> 1; + std::cout << "bitA >> 1 = " << result << "\n"; +} \ No newline at end of file diff --git a/src/core/basics/README.md b/src/core/basics/README.md index aab72de..e6c1d1c 100644 --- a/src/core/basics/README.md +++ b/src/core/basics/README.md @@ -1,13 +1,9 @@ -# Theory +# Basic C++ ## 1. Initialization in C++ - C++ provides several ways to initialize objects. Each form has different semantics and use cases. ---- - ### 1.1 Default Initialization - Performed when an object is created **without any initializer**. ```cpp @@ -21,7 +17,6 @@ new T; --- ### 1.2 Value Initialization - Performed when an object is created with an **empty initializer**. ```cpp From 3d5a74fc440d855a4ac336e33438917b81308bc3 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Apr 2026 12:31:34 +0700 Subject: [PATCH 5/6] Update README --- tests/README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/README.md b/tests/README.md index f332245..e1e8592 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,12 +1,19 @@ # GoogleTest +- Ref: https://google.github.io/googletest/ - GoogleTest helps you write better C++ tests. -## 1. Basic Concepts -- **assertions:** the statememts that check whether a condition is true. The result can be: - - success - - nonfatal failure - - fatal failure -- **test suite:** that contains one or many tests. -- **text fixture:** the class contain test suite used for multiple tests to share common objects and subroutines. +- Basic Concepts: + - **Assertions:** the statememts that check whether a condition is true. The result can be: + - success + - nonfatal failure + - fatal failure + - **Test Suite:** that contains one or many tests. + - **Text fixture:** the class contain test suite used for multiple tests to share common objects and subroutines. + +## 1. Assertions: +- **ASSERT_** generates fatal failures and **abort** the current function. +- **EXPECT_** generates nonfatal failures and don't abort the current function. (Preferred) +- To provide a custom failure message, simply stream it into the macro using **`<<`** +- Ref: https://google.github.io/googletest/reference/assertions.html ## 2. Test Fixtures: Using the Same Data Configuration for Multiple Tests - To create a fixture class: @@ -16,7 +23,7 @@ - write a default destructor or `TearDown()` function to release resources. - use `TEST_F(TestFixtureClassName, TestName)` instead of `TEST()` ->All documentation is covered in the official github repo. The primer documentation also covers a lot of information regarding the test macros. You could use the following summary and the examples linked to choose what you want to use. (https://stackoverflow.com/questions/58600728/what-is-the-difference-between-test-test-f-and-test-p) +> All documentation is covered in the official github repo. The primer documentation also covers a lot of information regarding the test macros. You could use the following summary and the examples linked to choose what you want to use. (https://stackoverflow.com/questions/58600728/what-is-the-difference-between-test-test-f-and-test-p) - **TEST()** is useful when you want to write unit tests for static or global functions or simple classes. - **TEST_F()** is useful when you need access to objects and subroutines in the unit test. @@ -100,4 +107,5 @@ int main(int argc, char **argv) { +) first, you use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; +) next, you create some mock objects and specify its expectations and behavior using an intuitive syntax; +) then you exercise code that uses the mock objects. gMock will catch any violation to the expectations as soon as it arises. + TBD https://google.github.io/googletest/gmock_for_dummies.html From 44bf51596c0b3132f3a6eb5775ca7e3b274ff032 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Apr 2026 17:30:25 +0700 Subject: [PATCH 6/6] Refactor --- .vscode/launch.json | 4 +- src/CMakeLists.txt | 8 - src/ap/mvc/model/SharedData.h | 1 - src/ap/mvc/view/DisplayWidget.h | 1 - src/ap/simple_ap.cpp | 96 +++--- src/cembedded/README.md | 321 ----------------- src/core/CMakeLists.txt | 24 +- src/core/basics/InitializeVariable.cpp | 1 - src/core/class/Abstraction.cpp | 0 src/core/class/Binding.cpp | 37 +- src/core/class/CConstructors.cpp | 325 ------------------ src/core/class/CDestructors.cpp | 73 ---- src/core/class/Constructor.cpp | 324 +++++++++++++++++ src/core/class/Destructor.cpp | 72 ++++ src/core/class/Inheritance.cpp | 0 src/core/class/Polymorphism.cpp | 0 src/core/class/README.md | 71 ++-- src/core/class/Relationship.cpp | 38 +- src/core/class/RoleOfThreeFiveZero.cpp | 110 +++--- src/core/class/SallowDeepCopying.cpp | 82 ++--- src/core/class/VirtualBase.cpp | 8 +- src/core/concurrency/FuturePromise.cpp | 12 +- src/core/concurrency/RaceCondition.cpp | 18 +- src/core/concurrency/SharingData.cpp | 9 +- src/core/concurrency/ThreadManagement.cpp | 33 +- src/core/container/sequence/Array.cpp | 19 +- src/core/container/unordered/UnorderedMap.cpp | 9 +- .../CArray.cpp => datatype/Array.cpp} | 6 +- src/core/datatype/Enum.cpp | 53 +++ src/core/datatype/Fundamental.cpp | 62 ++++ .../CPointers.cpp => datatype/Pointer.cpp} | 54 +-- .../Reference.cpp} | 31 +- .../CStruct.cpp => datatype/Struct.cpp} | 20 +- .../TypeConVersions.cpp | 94 ++--- .../CUnion.cpp => datatype/Union.cpp} | 8 +- src/core/datatypes/CEnum.cpp | 52 --- src/core/datatypes/Fundamental.cpp | 63 ---- src/core/datetime/{CTime.cpp => Time.cpp} | 6 +- src/core/exception/BasicHandle.cpp | 3 +- src/core/exception/README.md | 21 +- src/core/exception/ThrowNoexcept.cpp | 18 +- src/core/expression/FunctionPointer.cpp | 15 +- src/core/filehandle/BinaryFileHandling.cpp | 36 +- src/core/filehandle/FileIO.cpp | 52 +-- src/core/filehandle/IOStream.cpp | 14 +- src/core/filehandle/OutputFormatting.cpp | 22 +- src/core/filehandle/StringStream.cpp | 8 +- src/core/overloading/AllocationOperator.cpp | 22 +- src/core/overloading/ArithmeticOperator.cpp | 6 +- src/core/overloading/AssignmentOperator.cpp | 12 +- .../overloading/ClassMemberAccessOperator.cpp | 18 +- src/core/overloading/ComparisonOperator.cpp | 6 +- src/core/overloading/IOOperator.cpp | 6 +- src/core/overloading/InDecOperator.cpp | 10 +- src/core/overloading/ParenthesisOperator.cpp | 6 +- src/core/overloading/SubscriptOperator.cpp | 6 +- src/core/overloading/TypeCast.cpp | 16 +- src/core/overloading/UnaryOperator.cpp | 12 +- src/core/smart_pointer/Shared.cpp | 16 +- src/core/smart_pointer/Unique.cpp | 18 +- src/core/smart_pointer/Weak.cpp | 20 +- .../string/{BasicString.cpp => CString.cpp} | 98 +++--- src/core/string/StdString.cpp | 50 +-- src/core/string/StringFormatting.cpp | 24 +- src/core/utils/StdAlgorithm.cpp | 4 +- src/dp/behavioral/ChainOfCommand.cpp | 78 ++--- src/dp/behavioral/Command.cpp | 73 ++-- src/dp/behavioral/Iterator.cpp | 79 +++-- src/dp/behavioral/Mediator.cpp | 66 ++-- src/dp/behavioral/Memento.cpp | 108 +++--- src/dp/behavioral/Observer.cpp | 68 ++-- src/dp/behavioral/State.cpp | 54 ++- src/dp/behavioral/Strategy.cpp | 42 +-- src/dp/behavioral/TemplateMethod.cpp | 27 +- src/dp/behavioral/Visitor.cpp | 56 +-- src/dp/creational/AbstractFactory.cpp | 23 +- src/dp/creational/Builder.cpp | 77 ++--- src/dp/creational/FactoryMethod.cpp | 25 +- src/dp/creational/Prototype.cpp | 55 +-- src/dp/creational/Singleton.cpp | 38 +- src/dp/structural/Adapter.cpp | 65 ++-- src/dp/structural/Bridge.cpp | 42 +-- src/dp/structural/Composite.cpp | 186 +++++----- src/dp/structural/Decorator.cpp | 78 ++--- src/dp/structural/Facade.cpp | 136 +++++--- src/dp/structural/Flyweight.cpp | 85 ++--- src/dp/structural/Proxy.cpp | 116 +++---- src/exercise/CMakeLists.txt | 9 - src/exercise/DriverAccount.cpp | 77 ----- src/exercise/DriverStudentManager.cpp | 70 ---- src/exercise/account/Account.cpp | 65 ---- src/exercise/account/Account.h | 22 -- src/exercise/account/CMakeLists.txt | 10 - src/exercise/student_manager/CMakeLists.txt | 16 - src/exercise/student_manager/Manager.cpp | 144 -------- src/exercise/student_manager/Manager.h | 23 -- src/exercise/student_manager/Student.cpp | 74 ---- src/exercise/student_manager/Student.h | 31 -- src/main.cpp | 82 +++-- src/socket/multiple_client/MultiTCPServer.cpp | 2 +- src/socket/multiple_client/MultiTCPServer.h | 6 +- src/socket/simple_tcp/SimpleTCPClient.cpp | 3 +- src/socket/simple_tcp/TCPClient.cpp | 16 +- src/socket/simple_tcp/TCPClient.h | 9 +- src/socket/simple_tcp/TCPServer.cpp | 13 +- src/socket/simple_tcp/TCPServer.h | 12 +- 106 files changed, 2065 insertions(+), 2880 deletions(-) delete mode 100644 src/cembedded/README.md delete mode 100644 src/core/class/Abstraction.cpp delete mode 100644 src/core/class/CConstructors.cpp delete mode 100644 src/core/class/CDestructors.cpp create mode 100644 src/core/class/Constructor.cpp create mode 100644 src/core/class/Destructor.cpp delete mode 100644 src/core/class/Inheritance.cpp delete mode 100644 src/core/class/Polymorphism.cpp rename src/core/{datatypes/CArray.cpp => datatype/Array.cpp} (78%) create mode 100644 src/core/datatype/Enum.cpp create mode 100644 src/core/datatype/Fundamental.cpp rename src/core/{datatypes/CPointers.cpp => datatype/Pointer.cpp} (60%) rename src/core/{datatypes/CReferences.cpp => datatype/Reference.cpp} (75%) rename src/core/{datatypes/CStruct.cpp => datatype/Struct.cpp} (71%) rename src/core/{datatypes => datatype}/TypeConVersions.cpp (58%) rename src/core/{datatypes/CUnion.cpp => datatype/Union.cpp} (86%) delete mode 100644 src/core/datatypes/CEnum.cpp delete mode 100644 src/core/datatypes/Fundamental.cpp rename src/core/datetime/{CTime.cpp => Time.cpp} (87%) rename src/core/string/{BasicString.cpp => CString.cpp} (68%) delete mode 100644 src/exercise/CMakeLists.txt delete mode 100644 src/exercise/DriverAccount.cpp delete mode 100644 src/exercise/DriverStudentManager.cpp delete mode 100644 src/exercise/account/Account.cpp delete mode 100644 src/exercise/account/Account.h delete mode 100644 src/exercise/account/CMakeLists.txt delete mode 100644 src/exercise/student_manager/CMakeLists.txt delete mode 100644 src/exercise/student_manager/Manager.cpp delete mode 100644 src/exercise/student_manager/Manager.h delete mode 100644 src/exercise/student_manager/Student.cpp delete mode 100644 src/exercise/student_manager/Student.h diff --git a/.vscode/launch.json b/.vscode/launch.json index 99971cf..0f0f807 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,8 +5,8 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - // "program": "${workspaceFolder}/build/debug/bin/cpp_lab_project", // path to the executable - "program": "${workspaceFolder}/build/debug/bin/mvc_ap", // path to the executable + "program": "${workspaceFolder}/build/debug/bin/cpp_lab_project", // path to the executable + // "program": "${workspaceFolder}/build/debug/bin/mvc_ap", // path to the executable "args": [], "stopAtEntry": true, "cwd": "${workspaceFolder}", // working directory diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 00a3998..6d9f8b3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,6 @@ add_subdirectory(core) add_subdirectory(controller) add_subdirectory(dp) add_subdirectory(socket) -add_subdirectory(exercise) add_subdirectory(ap) # main application executable does NOT link to this library. @@ -26,7 +25,6 @@ add_executable(${PROJECT_NAME} ${SOCKET_SOURCES} ${CONTROLLER_SOURCES} ${DP_SOURCES} - ${EXCERCISE_SOURCES} ) # Add header include paths @@ -37,10 +35,4 @@ target_include_directories(${PROJECT_NAME} # Optional: add project-specific compiler options target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -) - -target_link_libraries(${PROJECT_NAME} - PRIVATE - ex_account - ex_student_manager ) \ No newline at end of file diff --git a/src/ap/mvc/model/SharedData.h b/src/ap/mvc/model/SharedData.h index 83f3349..26a3cbe 100644 --- a/src/ap/mvc/model/SharedData.h +++ b/src/ap/mvc/model/SharedData.h @@ -15,7 +15,6 @@ class SharedData { private: void notifyObservers(); - private: std::string data_; std::vector observers_; }; \ No newline at end of file diff --git a/src/ap/mvc/view/DisplayWidget.h b/src/ap/mvc/view/DisplayWidget.h index 48022da..9eddc48 100644 --- a/src/ap/mvc/view/DisplayWidget.h +++ b/src/ap/mvc/view/DisplayWidget.h @@ -11,7 +11,6 @@ class DisplayWidget : public Gtk::Box, public IObserver { private: void updateLabel(const std::string& text); - private: std::string color_; Gtk::Frame frame_; Gtk::Box innerBox_; diff --git a/src/ap/simple_ap.cpp b/src/ap/simple_ap.cpp index 9d297cd..4b23329 100644 --- a/src/ap/simple_ap.cpp +++ b/src/ap/simple_ap.cpp @@ -6,94 +6,94 @@ class MainWindow : public Gtk::Window { // --- Layout Containers --- - Gtk::Box m_mainLayout; - Gtk::Box m_topRowLayout; + Gtk::Box m_mainLayout_; + Gtk::Box m_topRowLayout_; // --- Widgets --- // We must declare everything here so that the buttons are accessible // Editor - Gtk::Frame frame_Editor; - Gtk::Box m_boxEditor; - Gtk::Entry entry_Input; - Gtk::Button button_Update; + Gtk::Frame frame_Editor_; + Gtk::Box m_boxEditor_; + Gtk::Entry entry_Input_; + Gtk::Button button_Update_; // Monitor A - Gtk::Frame frame_MonitorA; - Gtk::Box m_boxMonitorA; - Gtk::Label m_labelMonitorA; + Gtk::Frame frame_MonitorA_; + Gtk::Box m_boxMonitorA_; + Gtk::Label m_labelMonitorA_; // Monitor B - Gtk::Frame frame_MonitorB; - Gtk::Box m_boxMonitorB; - Gtk::Label m_labelMonitorB; + Gtk::Frame frame_MonitorB_; + Gtk::Box m_boxMonitorB_; + Gtk::Label m_labelMonitorB_; public: MainWindow() - : m_mainLayout(Gtk::Orientation::VERTICAL), - m_topRowLayout(Gtk::Orientation::HORIZONTAL), - m_boxEditor(Gtk::Orientation::VERTICAL), - m_boxMonitorA(Gtk::Orientation::VERTICAL), - m_boxMonitorB(Gtk::Orientation::VERTICAL) { + : m_mainLayout_(Gtk::Orientation::VERTICAL), + m_topRowLayout_(Gtk::Orientation::HORIZONTAL), + m_boxEditor_(Gtk::Orientation::VERTICAL), + m_boxMonitorA_(Gtk::Orientation::VERTICAL), + m_boxMonitorB_(Gtk::Orientation::VERTICAL) { set_title("No-MVC (Coupled) Demo"); set_default_size(600, 400); // 1. SETUP UI (Visually identical to MVC) // --- Monitor A --- - frame_MonitorA.set_label("ZONE 2: MONITOR A (Blue)"); - m_labelMonitorA.set_markup( + frame_MonitorA_.set_label("ZONE 2: MONITOR A (Blue)"); + m_labelMonitorA_.set_markup( "Initial Data"); - m_boxMonitorA.append(m_labelMonitorA); - frame_MonitorA.set_child(m_boxMonitorA); - frame_MonitorA.set_hexpand(true); // Stretch + m_boxMonitorA_.append(m_labelMonitorA_); + frame_MonitorA_.set_child(m_boxMonitorA_); + frame_MonitorA_.set_hexpand(true); // Stretch // --- Monitor B --- - frame_MonitorB.set_label("ZONE 3: MONITOR B (Red)"); - m_labelMonitorB.set_markup( + frame_MonitorB_.set_label("ZONE 3: MONITOR B (Red)"); + m_labelMonitorB_.set_markup( "Initial Data"); - m_boxMonitorB.append(m_labelMonitorB); - frame_MonitorB.set_child(m_boxMonitorB); - frame_MonitorB.set_hexpand(true); + m_boxMonitorB_.append(m_labelMonitorB_); + frame_MonitorB_.set_child(m_boxMonitorB_); + frame_MonitorB_.set_hexpand(true); // --- Editor --- - frame_Editor.set_label("ZONE 1: EDITOR"); - entry_Input.set_text("Initial Data"); - button_Update.set_label("Direct Update"); // Live updates - m_boxEditor.append(entry_Input); - m_boxEditor.append(button_Update); - frame_Editor.set_child(m_boxEditor); + frame_Editor_.set_label("ZONE 1: EDITOR"); + entry_Input_.set_text("Initial Data"); + button_Update_.set_label("Direct Update"); // Live updates + m_boxEditor_.append(entry_Input_); + m_boxEditor_.append(button_Update_); + frame_Editor_.set_child(m_boxEditor_); // --- Layout --- - m_topRowLayout.append(frame_MonitorA); - m_topRowLayout.append(frame_MonitorB); - m_mainLayout.append(m_topRowLayout); - m_mainLayout.append(frame_Editor); + m_topRowLayout_.append(frame_MonitorA_); + m_topRowLayout_.append(frame_MonitorB_); + m_mainLayout_.append(m_topRowLayout_); + m_mainLayout_.append(frame_Editor_); // Margin for aesthetics - m_boxEditor.set_margin(10); - m_boxEditor.set_spacing(5); - m_boxMonitorA.set_margin(20); - m_boxMonitorB.set_margin(20); - set_child(m_mainLayout); + m_boxEditor_.set_margin(10); + m_boxEditor_.set_spacing(5); + m_boxMonitorA_.set_margin(20); + m_boxMonitorB_.set_margin(20); + set_child(m_mainLayout_); // 2. LOGIC HANDLING // Here, the button must "know" exactly who m_labelMonitorA and m_labelMonitorB are. // It directly controls the other widgets. // (THE BAD PART) - button_Update.signal_clicked().connect([this]() { + button_Update_.signal_clicked().connect([this]() { // Step 1: Get data directly from UI (Entry) - std::string text = entry_Input.get_text(); + std::string text = entry_Input_.get_text(); // There may be processing logic here (Validating...) if (text.empty()) return; // Step 2: Update Monitor A (Hard-coded) directly - m_labelMonitorA.set_markup("" + - text + ""); + m_labelMonitorA_.set_markup("" + + text + ""); // Step 3: Update Monitor B (Hard-coded) directly - m_labelMonitorB.set_markup("" + - text + ""); + m_labelMonitorB_.set_markup("" + + text + ""); std::cout << "Updated directly without Model!" << std::endl; }); } diff --git a/src/cembedded/README.md b/src/cembedded/README.md deleted file mode 100644 index b0de8e5..0000000 --- a/src/cembedded/README.md +++ /dev/null @@ -1,321 +0,0 @@ -# 1. Core C Basics for Embedded Systems - -**Topics Covered:** - -- 1.1 Variables & Data Types -- 1.2 Operators & Control Flow -- 1.3 Functions -- 1.4 Arrays & Strings -- 1.5 Basic Input/Output -- 1.6 Practice Problems - -## 1.1 Variables & Data Types - -**What is a Variable?** - -A variable is a named location in memory that stores data. Think of it as a labeled box -where you can put values and retrieve them later. - -**Note:** In embedded systems, understanding how much memory each data type uses is -CRITICAL because microcontrollers have limited RAM. - -**Common Data Types in C** - -| Data Type | Size (Typical) | Range | Use Case | -|-----------------|---------------|------------------------------------|-----------------------------------| -| char | 1 byte | -128 to 127 | Single characters, small integers | -| unsigned char | 1 byte | 0 to 255 | Sensor readings, register values | -| int (16-bit) | 2 bytes | -32,768 to 32,767 | Counters, calculations | -| unsigned int | 2 bytes | 0 to 65,535 (16-bit) | Always positive values | -| long | 4 bytes | -2,147,483,648 to 2,147,483,647 | Large numbers, timestamps | -| float | 4 bytes | ±3.4e±38 (~6–7 digits precision) | Decimal numbers (avoid in embedded!) | - -**Example Code:** -```c -// Declaring variables -int sensorValue = 0; // 16 or 32-bit integer -unsigned char ledState = 1; // 8-bit (0-255) -float temperature = 25.5; // Floating point -char deviceStatus = 'A'; // Single character - -// Why size matters in embedded: -unsigned char counter = 0; // Uses only 1 byte of RAM -int bigCounter = 0; // Uses 2 or 4 bytes of RAM -``` - -
- -## 1.2. Operators & Control Flow - -**Arithmetic Operators** - -Used for mathematical calculations: + (add), - (subtract), * (multiply), / (divide), % -(modulus/remainder) -```c -int a = 10, b = 3; -int sum = a + b; // 13 -int diff = a - b; // 7 -int product = a * b; // 30 -int quotient = a / b; // 3 (integer division!) -int remainder = a % b; // 1 -``` - -**Comparison Operators** - -Compare values and return true (1) or false (0): -```c -== (equal), -!= (not equal), -> (greater), -< (less), ->=, <= -``` - -**Logical Operators** - -Combine multiple conditions: && (AND), || (OR),! (NOT) - -```c -int temperature = 75; -int humidity = 60; - -// AND operator - both conditions must be true -if (temperature > 70 && humidity > 50) { - printf("Hot and humid!\n"); -} -``` - -**Control Flow: if/else** - -Makes decisions in your program based on conditions. - -```c -int temperature = 75; -if (temperature > 80) { - // Turn on cooling fan - fanState = 1; -} else if (temperature < 60) { - // Turn on heater - heaterState = 1; -} else { - // Temperature is fine - fanState = 0; - heaterState = 0; -} -``` - -**Loops: for and while** - -Repeat code multiple times. Essential for embedded systems! -```c -// for loop - when you know how many times to repeat -for (int i = 0; i < 10; i++) { - printf("%d ", i); // Prints: 0 1 2 3 4 5 6 7 8 9 -} - -// while loop - repeat while condition is true -int count = 0; -while (count < 5) { - printf("Count: %d\n", count); - count++; -} -``` - -> **Embedded Tip:** In embedded systems, you'll often use infinite loops: while(1) { } to -keep the microcontroller running continuously! - -## 1.3. Functions - -**What are Functions?** - -Functions are reusable blocks of code that perform a specific task. They help you -organize code and avoid repetition. - -**Function Structure** - -```c -return_type function_name(parameters) { - // code to execute - return value; // optional -} -``` - -**Example: Simple Functions** - -```c -// Function that returns sum of two numbers -int add(int a, int b) { - return a + b; -} - -// Function that doesn't return anything (void) -void blinkLED(int times) { - for (int i = 0; i < times; i++) { - // Turn LED on - // Delay - // Turn LED off - // Delay - } -} - -// Using the functions -int main() { - int result = add(5, 3); // result = 8 - blinkLED(5); // Blink LED 5 times - return 0; -} -``` - -> **Why Functions Matter in Embedded:** Real embedded projects have functions like -readSensor(), updateDisplay(), checkButton() - breaking complex tasks into simple, -manageable pieces. - -## 1.4. Arrays & Strings - -**What is an Array?** - -An array is a collection of elements of the same type stored in consecutive memory -locations. Think of it as a row of boxes, each holding a value. - -**Declaring and Using Arrays** - -```c -// Declare an array of 5 integers -int sensorReadings[5]; - -// Initialize array with values -int ledPins[4] = {2, 3, 4, 5}; - -// Access array elements (index starts at 0!) -sensorReadings[0] = 100; // First element -sensorReadings[1] = 105; // Second element -sensorReadings[4] = 120; // Fifth element - -// Loop through array -for (int i = 0; i < 5; i++) { - printf("%d ", sensorReadings[i]); -} -``` - -**Strings in C** - -In C, strings are arrays of characters ending with a null terminator ('\0'). This is different -from other languages! - -```c -// Declaring strings -char deviceName[] = "Arduino"; // Automatically adds \ -char message[20] = "Hello World"; // Reserve 20 chars - -// Character array vs string -char name[6] = {'C', 'l', 'a', 'u', 'd', '\0'}; // Must add \ - -// Common string operations (need string.h) -#include -char str1[50] = "Hello"; -char str2[50] = "World"; -strcat(str1, str2); // Concatenate: str1 becomes "HelloWorld" -int len = strlen(str1); // Get length: 10 -strcpy(str1, "New"); // Copy: str1 becomes "New" -``` - -> **Important:** In embedded systems, you'll often use character arrays to store sensor -data, messages for displays, or communication buffers. - -## 1.5. Basic Input/Output - -**Console Output: printf()** - -`printf()` is used to print formatted output to the console. Essential for debugging -embedded systems! - -```c -#include - -int temperature = 25; -float voltage = 3.3; -char status = 'A'; - -// Format specifiers: -printf("Temperature: %d°C\n", temperature); // %d for integers -printf("Voltage: %.2f V\n", voltage); // %f for floats (.2 = 2 decimals) -printf("Status: %c\n", status); // %c for characters -printf("Hex value: 0x%X\n", 255); // %X for hexadecimal - -// Multiple values: -printf("Temp: %d, Voltage: %.1f\n", temperature, voltage); -``` - -**Console Input: scanf()** - -`scanf()` reads formatted input from the console. - -```c -int age; -char name[50]; - -printf("Enter your age: "); -scanf("%d", &age); // Note the & symbol! - -printf("Enter your name: "); -scanf("%s", name); // No & for arrays - -printf("Hello %s, you are %d years old!\n", name, age); -``` - -**Common Format Specifiers** - -| Specifier | Data Type | Example | -|---------------|----------------|------------------------------| -| %d or %i | int | printf("%d", 42); | -| %ld | long | printf("%lu", 255); | -| %u | unsigned int | printf("%u", 255); | -| %lu | uint32_t | printf("%lu", 255); | -| %f | float/double | printf("%.2f", 3.14); | -| %c | char | printf("%c", 'A'); | -| %s | string | printf("%s", "Hello"); | -| %x or %X | hexadecimal | printf("0x%X", 255); | -| %p | pointer | printf("%p", &var); | - - -## 1.6. Practice Problems - -**Problem 1: Temperature Converter** - -Write a program that converts temperature from Celsius to Fahrenheit using the -formula: F = (C × 9/5) + 32 - -// Your code here: -// 1. Declare a float variable for celsius -// 2. Use scanf to get input -// 3. Calculate fahrenheit -// 4. Print the result - - -**Problem 2: Even or Odd Checker** - -Write a program that takes a number and prints whether it's even or odd. (Hint: Use the -modulus operator %) - -**Problem 3: Sum Calculator with Loop** - -Write a program that takes a number N and calculates the sum of all numbers from 1 to -N using a for loop. -Example: If N = 5, sum = 1+2+3+4+5 = 15 - -**Problem 4: Array Average** - -Create an array of 5 sensor readings. Write a function that calculates and returns the -average value. - -**Problem 5: LED Blink Function** - -Write a function void blinkPattern(int count, int delayMs) that simulates blinking an LED. -Use printf to show LED ON/OFF states. - -**Problem 5: Write a program that** -- Takes 5 temperature readings into an array -- Calculates the average temperature -- If average > 75°F, print "COOLING NEEDED" -- If average < 65°F, print "HEATING NEEDED" -- Otherwise, print "TEMPERATURE OK" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index db6af89..f5a2a9c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -20,19 +20,19 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/linkage/sharing/external/constants.cpp # Fundamental data types - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/Fundamental.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/CArray.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/CReferences.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/CPointers.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/CEnum.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/CStruct.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/CUnion.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/datatypes/TypeConVersions.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Fundamental.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Array.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Reference.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Pointer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Enum.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Struct.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/Union.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datatype/TypeConVersions.cpp # Classes and object lifecycle ${CMAKE_CURRENT_SOURCE_DIR}/class/Friend.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/class/CConstructors.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/class/CDestructors.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/class/Constructor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/class/Destructor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/class/SallowDeepCopying.cpp ${CMAKE_CURRENT_SOURCE_DIR}/class/RoleOfThreeFiveZero.cpp ${CMAKE_CURRENT_SOURCE_DIR}/class/Relationship.cpp @@ -42,7 +42,7 @@ set(CORE_SOURCES # String handling ${CMAKE_CURRENT_SOURCE_DIR}/string/StringFormatting.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/string/BasicString.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/string/CString.cpp ${CMAKE_CURRENT_SOURCE_DIR}/string/StdString.cpp # Exception handling @@ -88,7 +88,7 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/overloading/AllocationOperator.cpp # Date and time - ${CMAKE_CURRENT_SOURCE_DIR}/datetime/CTime.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/datetime/Time.cpp # Concurrency ${CMAKE_CURRENT_SOURCE_DIR}/concurrency/ThreadManagement.cpp diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp index ad9b678..40ebbb9 100644 --- a/src/core/basics/InitializeVariable.cpp +++ b/src/core/basics/InitializeVariable.cpp @@ -33,7 +33,6 @@ struct Foo { void initialize_variable() { std::cout << "\n--- Variable Initialization Examples ---\n"; - // There are there common ways to intialize a variable // * 1) Default-initialization int init_default_var; Foo init_default_obj; diff --git a/src/core/class/Abstraction.cpp b/src/core/class/Abstraction.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/class/Binding.cpp b/src/core/class/Binding.cpp index 30b7080..2de6913 100644 --- a/src/core/class/Binding.cpp +++ b/src/core/class/Binding.cpp @@ -1,31 +1,37 @@ // cppcheck-suppress-file [functionStatic,duplInheritedMember] + #include #include "ExampleRegistry.h" + namespace { -namespace EarlyBinding { -using namespace std; +namespace early_binding { class Animal { public: virtual ~Animal() = default; void speak() { // NOT virtual - cout << "Animal speaks\n"; + std::cout << "Animal speaks\n"; + dump_++; } + + protected: + int dump_{0}; }; class Dog : public Animal { public: void speak() { // Hides Animal::speak() - cout << "Dog barks\n"; + std::cout << "Dog barks\n"; + dump_++; } }; void print(int x) { - cout << "int\n"; + std::cout << "int: " << x << "\n"; } void print(double x) { - cout << "double\n"; + std::cout << "double: " << x << "\n"; } void run() { @@ -33,25 +39,24 @@ void run() { Animal* a = new Dog(); a->speak(); // Early binding: Non-virtual member function - print(5); // Early binding: int version chosen at compile time + print(5); // Early binding: int version chosen at compile time + print(0.5F); // Early binding: float version chosen at compile time delete a; } -} // namespace EarlyBinding - -namespace LateBinding { -using namespace std; +} // namespace early_binding +namespace late_binding { class Animal { public: virtual ~Animal() = default; virtual void speak() { // Virtual! - cout << "Animal speaks\n"; + std::cout << "Animal speaks\n"; } }; class Dog : public Animal { public: - void speak() override { cout << "Dog barks\n"; } + void speak() override { std::cout << "Dog barks\n"; } }; void run() { @@ -60,7 +65,7 @@ void run() { a->speak(); // Late binding delete a; } -} // namespace LateBinding +} // namespace late_binding } // namespace class Binding : public IExample { @@ -70,8 +75,8 @@ class Binding : public IExample { std::string description() const override { return "Binding examples"; }; void execute() override { - EarlyBinding::run(); - LateBinding::run(); + early_binding::run(); + late_binding::run(); }; }; diff --git a/src/core/class/CConstructors.cpp b/src/core/class/CConstructors.cpp deleted file mode 100644 index c605dc3..0000000 --- a/src/core/class/CConstructors.cpp +++ /dev/null @@ -1,325 +0,0 @@ -// cppcheck-suppress-file [unusedVariable,unreadVariable] -#include -using namespace std; - -// NOTE: We can throw an exception in a constructor to signal an error, -// and then catch that error using a standard try-catch block -// where the object is being instantiated. - -// **1. Members initializer list constructor** -namespace InitializerList { -class CConstructors { - private: - int m_x, m_y, m_z; - - public: - CConstructors(int x, int y) : m_x(x), m_y(y) { - cout << "Called CConstructors(int x, int y) : m_x(x), m_y(y) \n"; - // m_z{0}; // error, it already initialized, so only can do assigment - // m_z(0); // error, it already initialized, so only can do assigment - m_z = 0; - } - - // using brace init - CConstructors(int x, int y, int z) : m_x{x}, m_y{y}, m_z{z} { - cout << "Called CConstructors(int x, int y, int z) : m_x{x}, m_y{y}, " - "m_z{z} \n"; - } - - // default arguments : must always be the RIGHTMOST parameters - explicit CConstructors(int x = 1) { - cout << "Called CConstructors(int x = 1) \n"; - m_x = x; - m_y = 0; - m_z = 0; - } - - // CConstructors() = default; error: - // ‘InitializerList::CConstructors::CConstructors(int)’ cannot be overloaded - // with ‘InitializerList::CConstructors::CConstructors(int x = 1)’ - - void print() const { - cout << "m_x = " << m_x << ", m_y = " << m_y << ", m_z = " << m_z << "\n"; - } -}; - -void constructers() { - cout << "\n--- InitializerList Constructer Examples ---\n"; - CConstructors obj; - CConstructors obj1 = CConstructors(1, 2); - obj1.print(); - - CConstructors obj2 = CConstructors(3, 4, 5); - obj2.print(); -} -} // namespace InitializerList - -// **2. Default constructor** -// - It is a constructor that accepts no arguments. -// - Generated if no constructors are declared -// - Initializes members: basic types uninitialized, class types call their default constructor -namespace Default { -class UConstructors { - public: - // User-defined default constructor without argument - UConstructors() { cout << "Called UConstructors() \n"; } -}; - -class IConstructors { - public: - // Implicit default constructor is generated by the compiler when the class - // has no user-declared constructors -}; - -class EConstructors { - public: - // we already create the constructor ourselves - // EConstructors(int a) - explicit EConstructors(float a) // explicit -> - // EConstructors obj2 = 1; [ERROR] - - { - cout << "Called explicit EConstructors(int a) \n"; - } - - // Explicit default constructor : also want the compiler to generate the - // default constructor. - EConstructors() = default; -}; - -void constructers() { - cout << "\n--- Default Constructer Examples ---\n"; - UConstructors obj1; - // UConstructors obj2(); // wrong, this is function declare - // FYI: - // void outer() - // { - // void helper(); - // helper(); // defined later in the same file - // } - - UConstructors obj3{}; - - IConstructors obj4; - IConstructors obj6{}; - - EConstructors obj7; - EConstructors obj9{}; - - EConstructors obj10(1.2); - EConstructors obj11{2}; -} -} // namespace Default - -// **3. Delegate constructor: allow to delegate initialization to another** -// constructor Never generated automatically -namespace Delegate { -class CConstructor { - private: - int m_x; - int m_y; - - public: - CConstructor(int x, int y) : m_x{x}, m_y{y} { - cout << "Called CConstructor(int x, int y) : m_x{x}, m_y{y} \n"; - } - - explicit CConstructor(int x) : CConstructor{x, 1} { - cout << "Called CConstructor(int x):CConstructor(x,0) \n"; - } - - CConstructor() : CConstructor(0) { - cout << "Called CConstructor() : CConstructor(0) \n"; - } - - void print() const { cout << "m_x = " << m_x << ", m_y = " << m_y << "\n"; } -}; - -void constructors() { - cout << "\n--- Delegate Constructer Examples ---\n"; - CConstructor obj1 = CConstructor(); - obj1.print(); -} -} // namespace Delegate - -// **4. Copy constructor: initialize an copy object with an existing object** -// - Generated if no copy/move constructor or `destructor` is declared -// - Performs memberwise (shallow) copy -// * Copy constructor -// Object obj1 = obj2 -// Object obj1(obj2) -// Object obj1{obj2} -// * Copy assigment -// obj1 = obj1 -namespace Copy { -class - ICConstructor // C++ will create a public implicit copy constructor for us - // if we do not provide a one. -{ - private: - int m_x; - int m_y; - - public: - ICConstructor(int x, int y) : m_x{x}, m_y{y} { - cout << "Called ICConstructor(int x, int y) : m_x{x}, m_y{y} \n"; - } - - void print() const { cout << "m_x = " << m_x << ", m_y = " << m_y << "\n"; } -}; - -class ECConstructor // explicitly define our own copy constructor -{ - private: - int m_x; - int m_y; - - public: - ECConstructor(int x, int y) : m_x{x}, m_y{y} { - cout << "Called ICConstructor(int x, int y) : m_x{x}, m_y{y} \n"; - } - - // Implicit Copy constructor if there is no desconstrutor - // using `default` keyword - // ECConstructor(const ECConstructor &ref) = default; - - // Explicit Copy constructor (a=ECConstructor(b)) - ECConstructor(const ECConstructor& ref) : m_x{ref.m_x}, m_y{ref.m_x} { - cout << "Called ECConstructor(const ECConstructor& ref) : m_x{ref.m_x}, " - "m_y{ref.m_x} \n"; - } - - // Copy assigment (a=b) - ECConstructor& operator=(const ECConstructor& other) { - if (this != &other) { - this->m_x = other.m_x; - this->m_y = other.m_y; - } - return *this; - } - - void print() const { cout << "m_x = " << m_x << ", m_y = " << m_y << "\n"; } -}; - -class DECConstructor // Delete the copy constructor so no copies can be made -{ - private: - int m_x; - int m_y; - - public: - DECConstructor(int x, int y) : m_x{x}, m_y{y} { - cout << "Called DECConstructor(int x, int y) : m_x{x}, m_y{y} \n"; - } - - // using `delete` keyword - DECConstructor(const DECConstructor& fraction) = delete; - - void print() const { cout << "m_x = " << m_x << ", m_y = " << m_y << "\n"; } -}; - -void constructors() { - cout << "\n--- Copy Constructer Examples ---\n"; - ICConstructor obj1 = ICConstructor(1, 2); - ICConstructor obj2{obj1}; - obj1.print(); - obj2.print(); - - ECConstructor obj3 = ECConstructor(3, 4); - ECConstructor obj4{obj3}; - obj3.print(); - obj4.print(); - - DECConstructor obj5 = DECConstructor(5, 6); - // DECConstructor obj6{obj5}; error - obj5.print(); -} -} // namespace Copy - -// **4. Move Constructor** -// - Move constructor and move assignment transfer resource ownership -// - from one object to another. This is usually cheaper than copying. -// - A move constructor is implicitly generated only if no user-declared -// copy constructor, move constructor, or destructor exists. -namespace Move { -class Model // C++ will create a public implicit copy constructor for us if we - // do not provide a one. -{ - private: - int m_x; - int m_y; - - public: - Model(int x, int y) : m_x{x}, m_y{y} { cout << "Call constructor \n"; } - - ~Model() { cout << "Call destructor \n"; } - - Model(const Model& other) : Model(other.m_x, other.m_y) { - cout << "Call copy constructor \n"; - } - - Model& operator=(const Model& other) { - cout << "Call copy assigment \n"; - if (this != &other) { - this->m_x = other.m_x; - this->m_y = other.m_y; - } - return *this; - } - - Model(Model&& source) noexcept : m_x(source.m_x), m_y(source.m_y) { - cout << "Call move constructor\n"; - - // reset source - source.m_x = 0; - source.m_y = 0; - } - - Model& operator=(Model&& source) noexcept { - cout << "Call move assigment \n"; - if (this != &source) { - this->m_x = source.m_x; - this->m_y = source.m_y; - - // reset source - source.m_x = 0; - source.m_y = 0; - } - - return *this; - } - - void print() const { cout << "m_x = " << m_x << ", m_y = " << m_y << "\n"; } -}; - -void constructers() { - cout << "\n--- Move Constructor Examples ---\n"; - Model a(10, 20); - - cout << "\nCase 1: Model b = std::move(a);\n"; - Model b = std::move(a); // move constructor - - cout << "\nCase 2: Model c(5,6); c = std::move(b);\n"; - Model c(5, 6); - c = std::move(b); // move assignment - cout << "\n"; -} -} // namespace Move - -#include "ExampleRegistry.h" - -class CConstructors : public IExample { - public: - std::string group() const override { return "core/class"; } - std::string name() const override { return "CConstructors"; } - std::string description() const override { return ""; } - void execute() override { - InitializerList::constructers(); - Default::constructers(); - Delegate::constructors(); - Copy::constructors(); - Move::constructers(); - } -}; - -REGISTER_EXAMPLE(CConstructors, "core/class", "CConstructors"); diff --git a/src/core/class/CDestructors.cpp b/src/core/class/CDestructors.cpp deleted file mode 100644 index 721c40a..0000000 --- a/src/core/class/CDestructors.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -using namespace std; - -// ** 1. Basic Destructor** -// - Generated if no destructor is declared -// - Calls destructors of members automatically -// - Does not free dynamically allocated memory unless you write it -namespace Basic { -class CDestructors { - public: - CDestructors() { cout << "Called CDestructors() \n"; } - - ~CDestructors() { cout << "Called ~CDestructors() \n"; } - - // Using `default` keyword - // ~CDestructors() = default; - - // Using `delete` // I forbid this destructor - // ~CDestructors() = delete; -}; - -void destructers() { - cout << "\n--- Basic Destructer Examples ---\n"; - { CDestructors obj; } -} -} // namespace Basic - -// **2. Virtual Destructor** -namespace Virtual { -class CDestructorsBase // final => cannot inherit -{ - public: - CDestructorsBase() { cout << "Called CDestructorsBase() \n"; } - - virtual ~CDestructorsBase() { cout << "Called ~CDestructorsBase() \n"; } - - // Using `default` keyword - // ~CDestructorsBase() = default; -}; - -class CDestructorsDerived : public CDestructorsBase { - public: - CDestructorsDerived() { cout << "Called CDestructorsDerived() \n"; } - - ~CDestructorsDerived() override { - cout << "Called ~CDestructorsDerived() \n"; - } -}; - -void destructers() { - cout << "\n--- Virtual Destructer Examples ---\n"; - CDestructorsDerived* derived = {new CDestructorsDerived()}; - CDestructorsBase* base{derived}; - delete base; - // without virtual -> only call ~CDestructorsBase() - // with virtual -> call ~CDestructorsBase() && ~CDestructorsDerived() -} -} // namespace Virtual - -#include "ExampleRegistry.h" - -class CDestructors : public IExample { - public: - std::string group() const override { return "core/class"; } - std::string name() const override { return "CDestructors"; } - std::string description() const override { return ""; } - void execute() override { - Basic::destructers(); - Virtual::destructers(); - } -}; - -REGISTER_EXAMPLE(CDestructors, "core/class", "CDestructors"); diff --git a/src/core/class/Constructor.cpp b/src/core/class/Constructor.cpp new file mode 100644 index 0000000..33d3d42 --- /dev/null +++ b/src/core/class/Constructor.cpp @@ -0,0 +1,324 @@ +// cppcheck-suppress-file [unusedVariable,unreadVariable] + +#include + +// NOTE: We can throw an exception in a constructor to signal an error, +// and then catch that error using a standard try-catch block +// where the object is being instantiated. + +// **1. Members initializer list constructor** +namespace initializer_list { +class Constructor { + private: + int x_, y_, z_; + + public: + Constructor(int x, int y) : x_(x), y_(y) { + std::cout << "Called Constructor(int x, int y) : x_(x), y_(y) \n"; + // z_{0}; // error, it already initialized, so only can do assigment + // z_(0); // error, it already initialized, so only can do assigment + z_ = 0; + } + + // using brace init + Constructor(int x, int y, int z) : x_{x}, y_{y}, z_{z} { + std::cout << "Called Constructor(int x, int y, int z) : x_{x}, y_{y}, " + "z_{z} \n"; + } + + // default arguments : must always be the RIGHTMOST parameters + explicit Constructor(int x = 1) { + std::cout << "Called Constructor(int x = 1) \n"; + x_ = x; + y_ = 0; + z_ = 0; + } + + // Constructor() = default; error: + // ‘InitializerList::Constructor::Constructor(int)’ cannot be overloaded + // with ‘InitializerList::Constructor::Constructor(int x = 1)’ + + void print() const { + std::cout << "x_ = " << x_ << ", y_ = " << y_ << ", z_ = " << z_ << "\n"; + } +}; + +void constructers() { + std::cout << "\n--- InitializerList Constructer Examples ---\n"; + Constructor obj; + Constructor obj1 = Constructor(1, 2); + obj1.print(); + + Constructor obj2 = Constructor(3, 4, 5); + obj2.print(); +} +} // namespace initializer_list + +// **2. Default constructor** +// - It is a constructor that accepts no arguments. +// - Generated if no constructors are declared +// - Initializes members: basic types uninitialized, class types call their default constructor +namespace default_constructor { +class UConstructors { + public: + // User-defined default constructor without argument + UConstructors() { std::cout << "Called UConstructors() \n"; } +}; + +class IConstructors { + public: + // Implicit default constructor is generated by the compiler when the class + // has no user-declared constructors +}; + +class EConstructors { + public: + // we already create the constructor ourselves + // EConstructors(int a) + explicit EConstructors(float /*a*/) // explicit -> + // EConstructors obj2 = 1; [ERROR] + + { + std::cout << "Called explicit EConstructors(int a) \n"; + } + + // Explicit default constructor : also want the compiler to generate the + // default constructor. + EConstructors() = default; +}; + +void constructers() { + std::cout << "\n--- Default Constructer Examples ---\n"; + UConstructors obj1; + // UConstructors obj2(); // wrong, this is function declare + // FYI: + // void outer() + // { + // void helper(); + // helper(); // defined later in the same file + // } + + UConstructors obj3{}; + + IConstructors obj4; + IConstructors obj6{}; + + EConstructors obj7; + EConstructors obj9{}; + + EConstructors obj10(1.2); + EConstructors obj11{2}; +} +} // namespace default_constructor + +// **3. Delegate constructor: allow to delegate initialization to another** +// constructor Never generated automatically +namespace delegate { +class Constructor { + private: + int x_; + int y_; + + public: + Constructor(int x, int y) : x_{x}, y_{y} { + std::cout << "Called Constructor(int x, int y) : x_{x}, y_{y} \n"; + } + + explicit Constructor(int x) : Constructor{x, 1} { + std::cout << "Called Constructor(int x):Constructor(x,0) \n"; + } + + Constructor() : Constructor(0) { + std::cout << "Called Constructor() : Constructor(0) \n"; + } + + void print() const { std::cout << "x_ = " << x_ << ", y_ = " << y_ << "\n"; } +}; + +void constructors() { + std::cout << "\n--- Delegate Constructer Examples ---\n"; + Constructor obj1 = Constructor(); + obj1.print(); +} +} // namespace delegate + +// **4. Copy constructor: initialize an copy object with an existing object** +// - Generated if no copy/move constructor or `destructor` is declared +// - Performs memberwise (shallow) copy +// * Copy constructor +// Object obj1 = obj2 +// Object obj1(obj2) +// Object obj1{obj2} +// * Copy assigment +// obj1 = obj1 +namespace copy { +class IConstructor // C++ will create a public implicit copy constructor for us + // if we do not provide a one. +{ + private: + int x_; + int y_; + + public: + IConstructor(int x, int y) : x_{x}, y_{y} { + std::cout << "Called IConstructor(int x, int y) : x_{x}, y_{y} \n"; + } + + void print() const { std::cout << "x_ = " << x_ << ", y_ = " << y_ << "\n"; } +}; + +class EConstructor // explicitly define our own copy constructor +{ + private: + int x_; + int y_; + + public: + EConstructor(int x, int y) : x_{x}, y_{y} { + std::cout << "Called IConstructor(int x, int y) : x_{x}, y_{y} \n"; + } + + // Implicit Copy constructor if there is no desconstrutor + // using `default` keyword + // EConstructor(const EConstructor &ref) = default; + + // Explicit Copy constructor (a=EConstructor(b)) + EConstructor(const EConstructor& ref) : x_{ref.x_}, y_{ref.x_} { + std::cout << "Called EConstructor(const EConstructor& ref) : x_{ref.x_}, " + "y_{ref.x_} \n"; + } + + // Copy assigment (a=b) + EConstructor& operator=(const EConstructor& other) { + if (this != &other) { + this->x_ = other.x_; + this->y_ = other.y_; + } + return *this; + } + + void print() const { std::cout << "x_ = " << x_ << ", y_ = " << y_ << "\n"; } +}; + +class DeConstructor // Delete the copy constructor so no copies can be made +{ + private: + int x_; + int y_; + + public: + DeConstructor(int x, int y) : x_{x}, y_{y} { + std::cout << "Called DeConstructor(int x, int y) : x_{x}, y_{y} \n"; + } + + // using `delete` keyword + DeConstructor(const DeConstructor& fraction) = delete; + + void print() const { std::cout << "x_ = " << x_ << ", y_ = " << y_ << "\n"; } +}; + +void constructors() { + std::cout << "\n--- Copy Constructer Examples ---\n"; + IConstructor obj1 = IConstructor(1, 2); + IConstructor obj2{obj1}; + obj1.print(); + obj2.print(); + + EConstructor obj3 = EConstructor(3, 4); + EConstructor obj4{obj3}; + obj3.print(); + obj4.print(); + + DeConstructor obj5 = DeConstructor(5, 6); + // DeConstructor obj6{obj5}; error + obj5.print(); +} +} // namespace copy + +// **4. Move Constructor** +// - Move constructor and move assignment transfer resource ownership +// - from one object to another. This is usually cheaper than copying. +// - A move constructor is implicitly generated only if no user-declared +// copy constructor, move constructor, or destructor exists. +namespace move { +class Model // C++ will create a public implicit copy constructor for us if we + // do not provide a one. +{ + private: + int x_; + int y_; + + public: + Model(int x, int y) : x_{x}, y_{y} { std::cout << "Call constructor \n"; } + + ~Model() { std::cout << "Call destructor \n"; } + + Model(const Model& other) : Model(other.x_, other.y_) { + std::cout << "Call copy constructor \n"; + } + + Model& operator=(const Model& other) { + std::cout << "Call copy assigment \n"; + if (this != &other) { + this->x_ = other.x_; + this->y_ = other.y_; + } + return *this; + } + + Model(Model&& source) noexcept : x_(source.x_), y_(source.y_) { + std::cout << "Call move constructor\n"; + + // reset source + source.x_ = 0; + source.y_ = 0; + } + + Model& operator=(Model&& source) noexcept { + std::cout << "Call move assigment \n"; + if (this != &source) { + this->x_ = source.x_; + this->y_ = source.y_; + + // reset source + source.x_ = 0; + source.y_ = 0; + } + + return *this; + } + + void print() const { std::cout << "x_ = " << x_ << ", y_ = " << y_ << "\n"; } +}; + +void constructers() { + std::cout << "\n--- Move Constructor Examples ---\n"; + Model a(10, 20); + + std::cout << "\nCase 1: Model b = std::move(a);\n"; + Model b = std::move(a); // move constructor + + std::cout << "\nCase 2: Model c(5,6); c = std::move(b);\n"; + Model c(5, 6); + c = std::move(b); // move assignment + std::cout << "\n"; +} +} // namespace move + +#include "ExampleRegistry.h" + +class Constructor : public IExample { + public: + std::string group() const override { return "core/class"; } + std::string name() const override { return "Constructor"; } + std::string description() const override { return ""; } + void execute() override { + initializer_list::constructers(); + default_constructor::constructers(); + delegate::constructors(); + copy::constructors(); + move::constructers(); + } +}; + +REGISTER_EXAMPLE(Constructor, "core/class", "Constructor"); diff --git a/src/core/class/Destructor.cpp b/src/core/class/Destructor.cpp new file mode 100644 index 0000000..6e4db9e --- /dev/null +++ b/src/core/class/Destructor.cpp @@ -0,0 +1,72 @@ +#include + +// ** 1. Basic Destructor** +// - Generated if no destructor is declared +// - Calls destructors of members automatically +// - Does not free dynamically allocated memory unless you write it +namespace basic { +class Destructor { + public: + Destructor() { std::cout << "Called Destructor() \n"; } + + ~Destructor() { std::cout << "Called ~Destructor() \n"; } + + // Using `default` keyword + // ~Destructor() = default; + + // Using `delete` // I forbid this destructor + // ~Destructor() = delete; +}; + +void destructers() { + std::cout << "\n--- Basic Destructer Examples ---\n"; + { Destructor obj; } +} +} // namespace basic + +// **2. Virtual Destructor** +namespace virtual_desctructor { +class DestructorBase // final => cannot inherit +{ + public: + DestructorBase() { std::cout << "Called DestructorBase() \n"; } + + virtual ~DestructorBase() { std::cout << "Called ~DestructorBase() \n"; } + + // Using `default` keyword + // ~DestructorBase() = default; +}; + +class DestructorDerived : public DestructorBase { + public: + DestructorDerived() { std::cout << "Called DestructorDerived() \n"; } + + ~DestructorDerived() override { + std::cout << "Called ~DestructorDerived() \n"; + } +}; + +void destructers() { + std::cout << "\n--- Virtual Destructer Examples ---\n"; + DestructorDerived* derived = {new DestructorDerived()}; + DestructorBase* base{derived}; + delete base; + // without virtual -> only call ~DestructorBase() + // with virtual -> call ~DestructorBase() && ~DestructorDerived() +} +} // namespace virtual_desctructor + +#include "ExampleRegistry.h" + +class Destructor : public IExample { + public: + std::string group() const override { return "core/class"; } + std::string name() const override { return "Destructor"; } + std::string description() const override { return ""; } + void execute() override { + basic::destructers(); + virtual_desctructor::destructers(); + } +}; + +REGISTER_EXAMPLE(Destructor, "core/class", "Destructor"); diff --git a/src/core/class/Inheritance.cpp b/src/core/class/Inheritance.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/class/Polymorphism.cpp b/src/core/class/Polymorphism.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/class/README.md b/src/core/class/README.md index 5b58415..2446c72 100644 --- a/src/core/class/README.md +++ b/src/core/class/README.md @@ -1,3 +1,17 @@ +# Classes +- **A class** is a user-defined blueprint used to create objects. It defines the properties and behaviors that all objects of that type share. +- **An object** is an instance of a class. It represents a real entity and contains actual values for the class’s attributes. +- **An instance** is a specific object created from a class. (In practice, “object” and “instance” are often used interchangeably.) + +- **Four Pillars of OOP in C++:** + - **Abstraction** is the process of hiding the implementation details and only showing the essential details or features to the user. It allows to focus on what an object does rather than how it does it. It is achieved using abstract classes (classes that have at least one pure virtual function). + - **Encapsulation** is the process of bundling data and methods into a single unit (class) and restricting direct access to some components. Data is hidden and accessed through public methods. It is achieved using access specifiers like private, protected, and public. + - **Inheritance** is a mechanism where a derived class acquires the properties and behaviors of a base class, forming an is-a relationship. It improves code reuse and extensibility. It is implemented using : followed by an access specifier public, private, protected. + - **Polymorphism** means many forms. It allows the same interface (function or method) to behave differently depending on the context. + - It is achieved through: + - **Compile-time polymorphism**: function overloading, operator overloading + - **Runtime polymorphism**: virtual functions + ## 1. Friend - Friend declaration (classes and functions) allows certain classes or functions to access the private and protected members of another class. @@ -5,12 +19,13 @@ - It serves the same kind of role as the package access specifier in Java. - `a << b` C++ tries in this order: ```cpp -1 a.operator<<(b) -2 operator<<(a, b) (non-member function) +a.operator<<(b) +operator<<(a, b) (non-member function) X OP Y operator OP (type_of_X, type_of_Y) ``` + ### 1.2. Member of Another Class: - It give access to only once specific function. ### 1.3. Class @@ -60,7 +75,7 @@ public: }; ``` -## 2.2. Aggregations +### 2.2. Aggregations - **Has-a, weak ownership** - The member is part of the class - The member can belong to more than one class at a time @@ -100,7 +115,7 @@ public: }; ``` -## 2.3. Associations +### 2.3. Associations - **Uses-a, loose relationship** - The associated member is otherwise unrelated to the class - The associated member can belong to more than one class at a time @@ -130,7 +145,7 @@ public: }; ``` -## 2.4. Dependency +### 2.4. Dependency - **Denpends-on** - One class uses another class to perform a task. - It is temporarily created, used, and then destroyed, or passed into a member function from an external source. @@ -167,7 +182,7 @@ public: }; ``` -## 2.5. Container +### 2.5. Container - The class one class provides a container to hold multiple objects of another type - UML ```cpp @@ -264,48 +279,4 @@ public: void start(); }; }; -``` - -## Type Cast -- C-style cast is unsafe, so we should use dynamic_cast or static_cast instead. For example: -```cpp -#include -using namespace std; - -class Car { -public: - virtual ~Car() {} -}; - -class PassCar : public Car { -private: - int passengers = 5; -public: - void display() { - cout << passengers << endl; - } -}; - -class Truck : public Car { -private: - int a =1; -public: - void setAxle1s() { - cout << "Truck axles set1\n"; - } - void setAxles() { - cout << "Truck axles set\n"; - } -}; - -int main() { - Car* car = new Truck(); - - // -style cast - PassCar* p = (PassCar*)car; - - p->display(); - - delete car; -} ``` \ No newline at end of file diff --git a/src/core/class/Relationship.cpp b/src/core/class/Relationship.cpp index ed50a60..be30d7c 100644 --- a/src/core/class/Relationship.cpp +++ b/src/core/class/Relationship.cpp @@ -4,7 +4,7 @@ namespace { -namespace Composition { +namespace composition { // Engine is a part of the Car // Engine is managed by the Car class Engine { @@ -19,16 +19,16 @@ class Car { ~Car() { std::cout << "Car destroyed\n"; } private: - Engine engine; // composition + Engine engine_; // composition }; void run() { std::cout << "\n---Composition---\n"; Car car; } -}; // namespace Composition +}; // namespace composition -namespace Aggregations { +namespace aggregations { // Teacher is a part of the Department // Teacher can belong to one or more Department // Department does not managed Patient existence @@ -44,10 +44,10 @@ class Teacher { class Department { private: - Teacher* teacher; // aggregation + Teacher* teacher_; // aggregation public: - explicit Department(Teacher* t) : teacher(t) { + explicit Department(Teacher* t) : teacher_(t) { std::cout << "Department created \n"; } @@ -62,11 +62,11 @@ void run() { Department dep2{&t}; } } -}; // namespace Aggregations +}; // namespace aggregations // Doctor uses Patient // Doctor does not managed Patient existence -namespace Associations { +namespace associations { class Patient { public: Patient() { std::cout << "Patient created \n"; } @@ -87,10 +87,10 @@ void run() { Doctor d{}; d.treat(p); } -} // namespace Associations +} // namespace associations // Car creates and uses Logger to log -namespace Dependency { +namespace dependency { class Logger { public: Logger() { std::cout << "Logger created \n"; } @@ -115,9 +115,9 @@ void run() { Car car{}; car.start(); } -} // namespace Dependency +} // namespace dependency -namespace Container { +namespace container { // class Library1 { // private: // std::vector books; // copy values @@ -127,9 +127,9 @@ namespace Container { // private: // std::vector teachers; // store pointers // }; -} // namespace Container +} // namespace container -namespace InnerClass { +namespace inner_class { class Car { public: class Engine { @@ -137,7 +137,7 @@ class Car { void start(); }; }; -} // namespace InnerClass +} // namespace inner_class } // namespace class Relationship : public IExample { @@ -147,10 +147,10 @@ class Relationship : public IExample { std::string description() const override { return "Relationship examples"; }; void execute() override { - Composition::run(); - Aggregations::run(); - Associations::run(); - Dependency::run(); + composition::run(); + aggregations::run(); + associations::run(); + dependency::run(); }; }; diff --git a/src/core/class/RoleOfThreeFiveZero.cpp b/src/core/class/RoleOfThreeFiveZero.cpp index 0f42b94..e9ed3b4 100644 --- a/src/core/class/RoleOfThreeFiveZero.cpp +++ b/src/core/class/RoleOfThreeFiveZero.cpp @@ -5,23 +5,23 @@ #include namespace { -namespace Problem { +namespace problem { class Model { private: - char* cstring; + char* cstring_; public: - explicit Model(const char* s = "") : cstring{nullptr} { + explicit Model(const char* s = "") : cstring_{nullptr} { if (s) { - cstring = new char[std::strlen(s) + 1]; // allocate - std::strcpy(cstring, s); // populate + cstring_ = new char[std::strlen(s) + 1]; // allocate + std::strcpy(cstring_, s); // populate } } // I. destructor ~Model() { // delete[] cstring; // [P2] Double call here - std::cout << "Deleted cstring at: " << static_cast(cstring) + std::cout << "Deleted cstring at: " << static_cast(cstring_) << "\n"; } @@ -33,12 +33,12 @@ class Model { // Helper functions const char* c_str() const // accessor { - return cstring; + return cstring_; } void set_first_char(char ch) { - if (cstring) - cstring[0] = ch; + if (cstring_) + cstring_[0] = ch; } }; @@ -60,51 +60,51 @@ void run() { << "\n[P2] Decontructor issue when releasing the shared pointer.\n"; } } -} // namespace Problem +} // namespace problem // Rule of Three: define // - destructor // - copy constructor // - copy assignment -namespace RoleOfThree { +namespace role_of_three { class Model { private: - char* cstring; + char* cstring_; public: - explicit Model(const char* s = "") : cstring{nullptr} { + explicit Model(const char* s = "") : cstring_{nullptr} { if (s) { - cstring = new char[std::strlen(s) + 1]; // allocate - std::strcpy(cstring, s); // populate + cstring_ = new char[std::strlen(s) + 1]; // allocate + std::strcpy(cstring_, s); // populate } } // I. destructor ~Model() { - delete[] cstring; // [P2] Double call here - std::cout << "Deleted cstring at: " << static_cast(cstring) + delete[] cstring_; // [P2] Double call here + std::cout << "Deleted cstring at: " << static_cast(cstring_) << "\n"; } // II. copy constructor - Model(const Model& other) : Model(other.cstring) {} + Model(const Model& other) : Model(other.cstring_) {} // III. copy assignment Model& operator=(const Model& other) { Model temp(other); - std::swap(cstring, temp.cstring); + std::swap(cstring_, temp.cstring_); return *this; } // Helper functions const char* c_str() const // accessor { - return cstring; + return cstring_; } void set_first_char(char ch) { - if (cstring) - cstring[0] = ch; + if (cstring_) + cstring_[0] = ch; } }; @@ -132,38 +132,38 @@ void run() { << (str_move.c_str() ? str_move.c_str() : "null") << "\n"; } } -} // namespace RoleOfThree +} // namespace role_of_three // Rule of Five: Rule of Three and define // - move constructor // - move assignment -namespace RoleOfFive { +namespace role_of_five { class Model { private: - char* cstring; + char* cstring_; public: - explicit Model(const char* s = "") : cstring{nullptr} { + explicit Model(const char* s = "") : cstring_{nullptr} { if (s) { - cstring = new char[std::strlen(s) + 1]; // allocate - std::strcpy(cstring, s); // populate + cstring_ = new char[std::strlen(s) + 1]; // allocate + std::strcpy(cstring_, s); // populate } } // I. destructor ~Model() { - delete[] cstring; // [P2] Double call here - std::cout << "Deleted cstring at: " << static_cast(cstring) + delete[] cstring_; // [P2] Double call here + std::cout << "Deleted cstring at: " << static_cast(cstring_) << "\n"; } // II. copy constructor - Model(const Model& other) : Model(other.cstring) {} + Model(const Model& other) : Model(other.cstring_) {} // III. copy assignment Model& operator=(const Model& other) { Model temp(other); - std::swap(cstring, temp.cstring); + std::swap(cstring_, temp.cstring_); return *this; } @@ -171,23 +171,23 @@ class Model { // noexcept is a specifier that indicates a function will not throw // exceptions. Model(Model&& other) noexcept - : cstring(std::exchange(other.cstring, nullptr)){}; + : cstring_(std::exchange(other.cstring_, nullptr)){}; // V. move assignment Model& operator=(Model&& other) noexcept { - std::swap(cstring, other.cstring); + std::swap(cstring_, other.cstring_); return *this; } // Helper functions const char* c_str() const // accessor { - return cstring; + return cstring_; } void set_first_char(char ch) { - if (cstring) - cstring[0] = ch; + if (cstring_) + cstring_[0] = ch; } }; @@ -215,37 +215,37 @@ void run() { << (str_move.c_str() ? str_move.c_str() : "null") << "\n"; } } -} // namespace RoleOfFive +} // namespace role_of_five // Rule of Zero: use RAII (std::string, std::vector, smart pointers,...), no // need to define any special functions except constructor -namespace RoleOfZero { -class base_of_five_defaults { +namespace role_of_zero { +class BaseOfFiveDefaults { public: - base_of_five_defaults(const base_of_five_defaults&) = default; - base_of_five_defaults(base_of_five_defaults&&) = default; - base_of_five_defaults& operator=(const base_of_five_defaults&) = default; - base_of_five_defaults& operator=(base_of_five_defaults&&) = default; - virtual ~base_of_five_defaults() = default; + BaseOfFiveDefaults(const BaseOfFiveDefaults&) = default; + BaseOfFiveDefaults(BaseOfFiveDefaults&&) = default; + BaseOfFiveDefaults& operator=(const BaseOfFiveDefaults&) = default; + BaseOfFiveDefaults& operator=(BaseOfFiveDefaults&&) = default; + virtual ~BaseOfFiveDefaults() = default; }; class Model { private: - std::string cstring; + std::string cstring_; // int* ptr; -> std::unique_ptr ptr; (exclusive ownership) // int* arr; -> std::vector arr; (automatic array management) // int* shared; -> std::shared_ptr shared; (shared ownership) public: - explicit Model(const std::string& str) : cstring{str} {} + explicit Model(const std::string& str) : cstring_{str} {} // Helper functions - const std::string c_str() const // accessor + std::string c_str() const // accessor { - return cstring; + return cstring_; } - void set_first_char(char ch) { cstring.at(0) = ch; } + void set_first_char(char ch) { cstring_.at(0) = ch; } }; void run() { @@ -269,7 +269,7 @@ void run() { std::cout << " str_move.c_str() = " << str_move.c_str() << "\n"; } } -} // namespace RoleOfZero +} // namespace role_of_zero } // namespace #include "ExampleRegistry.h" @@ -280,10 +280,10 @@ class RoleOfThreeFiveZero : public IExample { std::string name() const override { return "RoleOfThreeFiveZero"; } std::string description() const override { return ""; } void execute() override { - Problem::run(); - RoleOfThree::run(); - RoleOfFive::run(); - RoleOfZero::run(); + problem::run(); + role_of_three::run(); + role_of_five::run(); + role_of_zero::run(); } }; diff --git a/src/core/class/SallowDeepCopying.cpp b/src/core/class/SallowDeepCopying.cpp index 2577d19..4b33661 100644 --- a/src/core/class/SallowDeepCopying.cpp +++ b/src/core/class/SallowDeepCopying.cpp @@ -3,17 +3,17 @@ #include namespace { -namespace Shallow { +namespace shallow { class Model { private: - int m_x{0}, m_y{1}; - int* ptr; + int x_{0}, y_{1}; + int* ptr_{}; public: // Default constructor: Model a = Model(1,2) - explicit Model(int x, int y, int z) : m_x{x}, m_y{y}, ptr{nullptr} { - ptr = new int; - *ptr = z; + explicit Model(int x, int y, int z) : x_{x}, y_{y} { + ptr_ = new int; + *ptr_ = z; } ~Model() { @@ -21,24 +21,24 @@ class Model { // Shallow copying makes both objects use the same pointer. // If one object deletes the pointer, the other object now // points to invalid memory. - // delete ptr; // Commented out on purpose for demo + // delete ptr_; // Commented out on purpose for demo } void changePtr(int value) { - if (ptr != nullptr) { - *ptr = value; + if (ptr_ != nullptr) { + *ptr_ = value; } } int getPtr() const { - if (ptr != nullptr) { - return *ptr; + if (ptr_ != nullptr) { + return *ptr_; } return 0; } // Implicit copy constructor: Model a{b}; - // Model(const Model &f) : m_x{f.m_x}, m_y{f.m_y} {} + // Model(const Model &f) : x_{f.x_}, y_{f.y_} {} // Implicit assignment operator (like the way compiler gen this function): // Model a = b; Model &operator=(const Model &f) @@ -50,8 +50,8 @@ class Model { // } // // do the copy - // m_x = f.m_x; - // m_y = f.m_y; + // x_ = f.x_; + // y_ = f.y_; // // return the existing object so we can chain this operator // return *this; @@ -64,49 +64,49 @@ void run() { obj2.changePtr(30); // [P2] std::cout << "\n=== Shallow Copy Demo ===\n"; - std::cout << "obj1.ptr = " << obj1.getPtr() << "\n"; - std::cout << "obj2.ptr = " << obj2.getPtr() << "\n"; + std::cout << "obj1.ptr_ = " << obj1.getPtr() << "\n"; + std::cout << "obj2.ptr_ = " << obj2.getPtr() << "\n"; } -} // namespace Shallow +} // namespace shallow // To do a deep copy on any non-null pointers being copied // Requires that we write our own `copy constructors` and `overloaded assignment // operators`. -namespace DeepCopying { +namespace deep_copying { class Model { private: - int m_x{0}, m_y{1}; - int* ptr; + int x_{0}, y_{1}; + int* ptr_{}; void deepCopy(const Model& source) { // sallow copy the normal fields - m_x = source.m_x; - m_y = source.m_y; + x_ = source.x_; + y_ = source.y_; - // deep copy the ptr field + // deep copy the ptr_ field // m_data is a pointer, so we need to deep copy it if it is non-null // first we need to deallocate any value that this Model is holding! - delete ptr; - if (source.ptr != nullptr) { + delete ptr_; + if (source.ptr_ != nullptr) { // allocate memory for our copy - ptr = new int; + ptr_ = new int; // do the copy - *ptr = *source.ptr; + *ptr_ = *source.ptr_; } else { - ptr = nullptr; + ptr_ = nullptr; } } public: // Constructor - explicit Model(int x, int y, int z) : m_x{x}, m_y{y}, ptr{nullptr} { - ptr = new int; - *ptr = z; + explicit Model(int x, int y, int z) : x_{x}, y_{y} { + ptr_ = new int; + *ptr_ = z; } // Destructor - ~Model() { delete ptr; } + ~Model() { delete ptr_; } // Copy constructor // no need to check self-copy [if (this != &source)] @@ -125,14 +125,14 @@ class Model { } void changePtr(int value) { - if (ptr != nullptr) { - *ptr = value; + if (ptr_ != nullptr) { + *ptr_ = value; } } int getPtr() const { - if (ptr != nullptr) { - return *ptr; + if (ptr_ != nullptr) { + return *ptr_; } return 0; } @@ -144,11 +144,11 @@ void run() { obj2.changePtr(30); std::cout << "\n=== Deep Copy Demo ===\n"; - std::cout << "obj1.ptr = " << obj1.getPtr() << "\n"; - std::cout << "obj2.ptr = " << obj2.getPtr() << "\n"; + std::cout << "obj1.ptr_ = " << obj1.getPtr() << "\n"; + std::cout << "obj2.ptr_ = " << obj2.getPtr() << "\n"; } -} // namespace DeepCopying +} // namespace deep_copying } // namespace #include "ExampleRegistry.h" @@ -159,8 +159,8 @@ class ShallowDeepCopying : public IExample { std::string name() const override { return "ShallowDeepCopying"; } std::string description() const override { return ""; } void execute() override { - Shallow::run(); - DeepCopying::run(); + shallow::run(); + deep_copying::run(); } }; diff --git a/src/core/class/VirtualBase.cpp b/src/core/class/VirtualBase.cpp index c72c06a..34f2098 100644 --- a/src/core/class/VirtualBase.cpp +++ b/src/core/class/VirtualBase.cpp @@ -3,7 +3,7 @@ #include "ExampleRegistry.h" namespace { -namespace Problem { +namespace problem { class PoweredDevice { public: PoweredDevice() { std::cout << "Powered Device created\n"; } @@ -57,7 +57,7 @@ void run() { } // namespace Problem -namespace VirtualBaseClasses { +namespace virtual_base_classes { class PoweredDevice { public: PoweredDevice() { std::cout << "Powered Device created\n"; } @@ -118,8 +118,8 @@ class VirtualBase : public IExample { std::string description() const override { return "VirtualBase examples"; }; void execute() override { - Problem::run(); - VirtualBaseClasses::run(); + problem::run(); + virtual_base_classes::run(); }; }; diff --git a/src/core/concurrency/FuturePromise.cpp b/src/core/concurrency/FuturePromise.cpp index d5e856f..d7464fd 100644 --- a/src/core/concurrency/FuturePromise.cpp +++ b/src/core/concurrency/FuturePromise.cpp @@ -6,7 +6,7 @@ #include "ExampleRegistry.h" -namespace Async { +namespace async { int async_worker() { std::cout << "[worker] started, needs 2000 ms\n"; std::this_thread::sleep_for(std::chrono::seconds(2)); @@ -45,9 +45,9 @@ void run() { std::cout << "[main] total time = " << total << " ms\n"; } -} // namespace Async +} // namespace async -namespace Simple { +namespace simple { void promise_worker(std::promise* prom) { std::cout << "[worker] started, needs 2000 ms\n"; std::this_thread::sleep_for(std::chrono::seconds(2)); @@ -91,7 +91,7 @@ void run() { thread.join(); } -} // namespace Simple +} // namespace simple class FuturePromise : public IExample { @@ -102,9 +102,9 @@ class FuturePromise : public IExample { } void execute() override { - Async::run(); + async::run(); - Simple::run(); + simple::run(); } }; diff --git a/src/core/concurrency/RaceCondition.cpp b/src/core/concurrency/RaceCondition.cpp index c0ed3c8..14f2290 100644 --- a/src/core/concurrency/RaceCondition.cpp +++ b/src/core/concurrency/RaceCondition.cpp @@ -5,7 +5,7 @@ #include #include "ExampleRegistry.h" -namespace Problem { +namespace problem { int glo_var = 0; void f1() { @@ -30,9 +30,9 @@ void run() { // expect: 200 ? std::cout << "glo_var: " << glo_var << '\n'; } -} // namespace Problem +} // namespace problem -namespace Mutex { +namespace mutex { int glo_var = 0; std::mutex g_mutex; @@ -63,9 +63,9 @@ void run() { // expect: 200 ? std::cout << "glo_var: " << glo_var << '\n'; } -} // namespace Mutex +} // namespace mutex -namespace Atomic { +namespace atomic { std::atomic glo_var = 0; void f1() { @@ -90,7 +90,7 @@ void run() { // expect: 200 ? std::cout << "glo_var: " << glo_var << '\n'; } -} // namespace Atomic +} // namespace atomic class RaceCondition : public IExample { @@ -101,9 +101,9 @@ class RaceCondition : public IExample { } void execute() override { - Problem::run(); - Atomic::run(); - Mutex::run(); + problem::run(); + atomic::run(); + mutex::run(); } }; diff --git a/src/core/concurrency/SharingData.cpp b/src/core/concurrency/SharingData.cpp index 6026b30..357dacb 100644 --- a/src/core/concurrency/SharingData.cpp +++ b/src/core/concurrency/SharingData.cpp @@ -1,4 +1,3 @@ -#include #include #include #include "ExampleRegistry.h" @@ -35,13 +34,13 @@ void run() { class SharingData : public IExample { - std::string group() const { return "core/concurrency"; } - std::string name() const { return "SharingData"; } - std::string description() const { + std::string group() const override { return "core/concurrency"; } + std::string name() const override { return "SharingData"; } + std::string description() const override { return "The examples for sharing data"; } - void execute() { run(); } + void execute() override { run(); } }; REGISTER_EXAMPLE(SharingData, "core/concurrency", "SharingData"); \ No newline at end of file diff --git a/src/core/concurrency/ThreadManagement.cpp b/src/core/concurrency/ThreadManagement.cpp index f5df7d4..87a3e9c 100644 --- a/src/core/concurrency/ThreadManagement.cpp +++ b/src/core/concurrency/ThreadManagement.cpp @@ -14,7 +14,7 @@ void checkJoinable(std::thread& thread) { } } // namespace -namespace ExceptionBeforeJoin { +namespace exception_before_join { class ThreadGuard { public: explicit ThreadGuard(std::thread& thread); @@ -66,9 +66,9 @@ void run() { std::cout << "\nrun finished\n"; } -} // namespace ExceptionBeforeJoin +} // namespace exception_before_join -namespace Detach { +namespace detach { void foo() { std::cout << "\nfoo started\n"; std::this_thread::sleep_for(std::chrono::microseconds(1000)); @@ -92,9 +92,9 @@ void run() { foo_thread.join(); std::cout << "\nrun finished\n"; } -} // namespace Detach +} // namespace detach -namespace Join { +namespace join { void callable() { for (size_t i = 0; i < 10; ++i) { std::cout << "callable " << i << '\n'; @@ -104,8 +104,9 @@ void callable() { } void run() { - unsigned int threadsNum = std::thread::hardware_concurrency(); - std::cout << "The number of hardware thread contexts: " << threadsNum << '\n'; + unsigned int threads_num = std::thread::hardware_concurrency(); + std::cout << "The number of hardware thread contexts: " << threads_num + << '\n'; std::cout << "\n---Join Ex---\n"; // create a thread object @@ -125,18 +126,20 @@ void run() { std::cout << "\nrun finished\n"; } -} // namespace Join +} // namespace join class ThreadManagement : public IExample { - std::string group() const { return "core/concurrency"; } - std::string name() const { return "ThreadManagement"; } - std::string description() const { return "The examples for "; } + std::string group() const override { return "core/concurrency"; } + std::string name() const override { return "ThreadManagement"; } + std::string description() const override { + return "The examples for "; + } - void execute() { - Join::run(); - Detach::run(); - ExceptionBeforeJoin::run(); + void execute() override { + join::run(); + detach::run(); + exception_before_join::run(); } }; diff --git a/src/core/container/sequence/Array.cpp b/src/core/container/sequence/Array.cpp index 64560ce..d5f25b4 100644 --- a/src/core/container/sequence/Array.cpp +++ b/src/core/container/sequence/Array.cpp @@ -31,11 +31,14 @@ void run() { std::cout << *(ptr_arr++) << " "; std::cout << std::endl; + // raw for loop for (std::size_t i = 0; i < m_array.size(); ++i) { std::cout << m_array.at(i) << " "; } + std::cout << std::endl; + // for range for (const int& e : m_array) { std::cout << e << " "; } @@ -49,10 +52,10 @@ void run() { } std::cout << std::endl; - auto rIt = m_array.rbegin(); - auto rItEnd = m_array.rend(); - for (; rIt != rItEnd; rIt++) { - std::cout << *rIt << " "; + auto r_it = m_array.rbegin(); + auto r_it_end = m_array.rend(); + for (; r_it != r_it_end; r_it++) { + std::cout << *r_it << " "; } std::cout << std::endl; @@ -60,17 +63,17 @@ void run() { std::cout << m_array.max_size() << std::endl; // fixed-size => max_size = size std::cout << m_array.size() << std::endl; - bool isEmpty = m_array.empty(); + bool is_empty = m_array.empty(); // 5) Operation - constexpr std::size_t xy = 4; + constexpr std::size_t kXy = 4; using Cell = std::array; - std::array board; + std::array board; board.fill({0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, 0}); // "▄▀"; // fill means fill all 16 Cell with "▄▀" // board = {Cell{0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, 0},Cell{0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, 0}}; for (size_t count{}; Cell c : board) - std::cout << c.data() << ((++count % xy) ? "" : "\n"); + std::cout << c.data() << ((++count % kXy) ? "" : "\n"); } } // namespace diff --git a/src/core/container/unordered/UnorderedMap.cpp b/src/core/container/unordered/UnorderedMap.cpp index fae0b00..2414c74 100644 --- a/src/core/container/unordered/UnorderedMap.cpp +++ b/src/core/container/unordered/UnorderedMap.cpp @@ -21,13 +21,13 @@ void run() { // 2) Modifiers m_map.insert({"k_4", 4}); - std::pair newElem1 = {"k_5", 0}; - m_map.insert(newElem1); + std::pair new_elem1 = {"k_5", 0}; + m_map.insert(new_elem1); std::string m_key = "k_6"; int m_value = 99; - auto newElem2 = std::make_pair(m_key, m_value); - m_map.insert(newElem2); + auto new_elem2 = std::make_pair(m_key, m_value); + m_map.insert(new_elem2); auto m_map2 = m_map; for (auto it = m_map.begin(); it != m_map.end();) { @@ -57,6 +57,7 @@ void run() { // 4) Make fun std::vector keys{}; + keys.reserve(m_map2.size()); for (auto const& [k, v] : m_map2) { keys.push_back(k); } diff --git a/src/core/datatypes/CArray.cpp b/src/core/datatype/Array.cpp similarity index 78% rename from src/core/datatypes/CArray.cpp rename to src/core/datatype/Array.cpp index cafe1dc..18d1514 100644 --- a/src/core/datatypes/CArray.cpp +++ b/src/core/datatype/Array.cpp @@ -21,10 +21,10 @@ void arrayExamples() { class CArray : public IExample { public: - std::string group() const override { return "core"; } - std::string name() const override { return "CArray"; } + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Array"; } std::string description() const override { return ""; } void execute() override { arrayExamples(); } }; -REGISTER_EXAMPLE(CArray, "core", "CArray"); +REGISTER_EXAMPLE(CArray, "core/datatype", "Array"); diff --git a/src/core/datatype/Enum.cpp b/src/core/datatype/Enum.cpp new file mode 100644 index 0000000..8c06e43 --- /dev/null +++ b/src/core/datatype/Enum.cpp @@ -0,0 +1,53 @@ +// cppcheck-suppress-file [unreadVariable] + +#include // for uint8_t +#include + +// A type defined in terms of other types + +// *0. Define some enums +// Unscope enum +enum BasicEnum { kEnumratorA, kEnumratorB, kEnumratorC }; + +// Scoped enum - enumrators are inside enum's scope +enum class ScopeEnumClass { kEnumratorA, kEnumratorB, kEnumratorC }; + +// Scoped enum inside a namespace +namespace enum_name_space { +enum class ScopeEnumClass { kEnumratorA, kEnumratorB, kEnumratorC }; +} + +// Scoped enum with explicit base type +enum class ScopeEnumClassB : uint8_t { + kEnumratorA = 0, + kEnumratorB = 1, + kEnumratorC = 2 +}; + +void enums() { + std::cout << "\n--- Enum Type Examples ---\n"; + // *1. Using unscope enum + BasicEnum unscope_e = kEnumratorA; + + // *2. Using scoped enum + ScopeEnumClass scope_e_c = ScopeEnumClass::kEnumratorA; + + // *3. Using scoped enum namespace + enum_name_space::ScopeEnumClass scope_e_c_n = + enum_name_space::ScopeEnumClass::kEnumratorA; + + // *4. Using scoped enum with base type + ScopeEnumClassB st = ScopeEnumClassB::kEnumratorA; +} + +#include "ExampleRegistry.h" + +class CEnum : public IExample { + public: + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Enum"; } + std::string description() const override { return "Compound type: Enum"; } + void execute() override { enums(); } +}; + +REGISTER_EXAMPLE(CEnum, "core/datatype", "Enum"); diff --git a/src/core/datatype/Fundamental.cpp b/src/core/datatype/Fundamental.cpp new file mode 100644 index 0000000..900012a --- /dev/null +++ b/src/core/datatype/Fundamental.cpp @@ -0,0 +1,62 @@ +#include + +// A basic type built into the core C++ language +void primative() { + std::cout << "\n--- Primative Type Examples ---\n"; + // Boolean + bool is_ready = true; + std::cout << "bool: " << is_ready << "\n"; + + // Character + char c = 'A'; + unsigned char uc = 200; + wchar_t wc = L'Ω'; // Greek Omega + // char8_t c8 = u8'A'; // UTF-8 + char16_t c16 = u'ß'; // UTF-16 + char32_t c32 = U'中'; // UTF-32 + std::cout << "char: " << c << "\n"; + std::cout << "unsigned char: " << static_cast(uc) << "\n"; + std::wcout << L"wchar_t: " << wc << L"\n"; + // std::cout << "char8_t: " << static_cast(c8) << "\n"; + std::cout << "char16_t: (UTF-16 code) " << static_cast(c16) << "\n"; + std::cout << "char32_t: (UTF-32 code) " << static_cast(c32) << "\n"; + + // Integer + short s = -10; + int i = 42; + unsigned int ui = 100; + long l = 123456L; + long long ll = 9876543210LL; + std::cout << "short: " << s << "\n"; + std::cout << "int: " << i << "\n"; + std::cout << "unsigned int: " << ui << "\n"; + std::cout << "long: " << l << "\n"; + std::cout << "long long: " << ll << "\n"; + + // Floating Point + float f = 3.14F; + double d = 2.718281828; + long double ld = 1.6180339887L; + std::cout << "float: " << f << "\n"; + std::cout << "double: " << d << "\n"; + std::cout << "long double: " << ld << "\n"; + + // Void + std::cout << "void: (no data type, used for functions)\n"; + + // pointer + int const* ptr = nullptr; + std::cout << "nullptr_t: " << ptr << "\n"; +} + +#include "ExampleRegistry.h" + +class Fundamental : public IExample { + public: + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Fundamental"; } + std::string description() const override { return "Fundamental"; } + void execute() override { primative(); } +}; + +REGISTER_EXAMPLE(Fundamental, "core/datatype", "Fundamental"); diff --git a/src/core/datatypes/CPointers.cpp b/src/core/datatype/Pointer.cpp similarity index 60% rename from src/core/datatypes/CPointers.cpp rename to src/core/datatype/Pointer.cpp index 2bbef1f..9568b4e 100644 --- a/src/core/datatypes/CPointers.cpp +++ b/src/core/datatype/Pointer.cpp @@ -1,31 +1,31 @@ +// cppcheck-suppress-file [unreadVariable] + #include -using namespace std; -// A type defined in terms of other types // Simple function to demonstrate function pointers int foo(int x) { - cout << "x = " << x << endl; + std::cout << "x = " << x << std::endl; return x; } void byPtr(int* x) { (*x)++; - cout << "x = " << *x << endl; + std::cout << "x = " << *x << std::endl; } void byConstPtr(const int* const x) { // *x++; // error - cout << "x = " << *x << endl; + std::cout << "x = " << *x << std::endl; } void byPtrConst(const int* x) { // *x++; // error - cout << "x = " << *x << endl; + std::cout << "x = " << *x << std::endl; } void byConstPtrConst(const int* const x) { // *x++; // error - cout << "x = " << *x << endl; + std::cout << "x = " << *x << std::endl; } static int global = 42; @@ -34,57 +34,57 @@ int* returnPtr() { } void pointers() { - cout << "\n--- Pointers Type Examples ---\n"; + std::cout << "\n--- Pointers Type Examples ---\n"; int a = 10; - cout << "a = " << a << "\n"; + std::cout << "a = " << a << "\n"; - // * 1. Pointer basics + // * 1. Basics const int* null_ptr = nullptr; - cout << "Address of nullptr (null_ptr): " << null_ptr << "\n"; + std::cout << "Address of nullptr (null_ptr): " << null_ptr << "\n"; // '&' gives the address of a variable int* ptr_a = &a; - cout << "Address of a (&a): " << &a << "\n"; - cout << "Value stored in pointer (ptr_a): " << ptr_a << "\n"; + std::cout << "Address of a (&a): " << &a << "\n"; + std::cout << "Value stored in pointer (ptr_a): " << ptr_a << "\n"; // '*' dereferences a pointer (accesses the value at that address) - cout << "Value of a via *ptr_a: " << *ptr_a << "\n"; + std::cout << "Value of a via *ptr_a: " << *ptr_a << "\n"; // Change value of a through its pointer *ptr_a = 2; - cout << "Value of a after *ptr_a = 2: " << a << "\n"; + std::cout << "Value of a after *ptr_a = 2: " << a << "\n"; // * 2. Pointer to const - [[maybe_unused]] const int const_var = 100; + const int const_var = 100; const int* ptr_const_var = &const_var; // *ptr_const_var = 10; // cannot modify the value through pointer - cout << "Value of ptr_const_var " << *ptr_const_var << "\n"; + std::cout << "Value of ptr_const_var " << *ptr_const_var << "\n"; ptr_const_var = &a; // can point somewhere else - cout << "Value of ptr_const_var " << *ptr_const_var << "\n"; + std::cout << "Value of ptr_const_var " << *ptr_const_var << "\n"; // * 3. Const pointer int* const const_ptr_a = &a; *const_ptr_a = 10; // can change value - // const_ptr_a = nullptr; //cannot point to another variable + // const_ptr_a = nullptr; //cannot point to another variable // * 4. Const pointer to const - [[maybe_unused]] const int* const const_ptr_const_var = &a; + const int* const const_ptr_const_var = &a; // *const_ptr_const_var = 10; // cannot modify the value through pointer // const_ptr_const_var = nullptr; //cannot point to another variable // * 5. Pointer to pointer int** ptr_ptr_a = new int*[10]; // dynamically allocate an array of 10 int* ptr_ptr_a[0] = &a; - cout << "Value via pointer-to-pointer (*ptr_ptr_a[0]): " << *ptr_ptr_a[0] - << "\n"; + std::cout << "Value via pointer-to-pointer (*ptr_ptr_a[0]): " << *ptr_ptr_a[0] + << "\n"; delete[] ptr_ptr_a; // always free heap memory // * 6. Void pointer (generic pointer) // void *void_ptr = static_cast(&a); void* void_ptr = &a; // C-style pointer casting [cstyleCast] - cout << "Value via void pointer (after casting): " - << *static_cast(void_ptr) << "\n"; + std::cout << "Value via void pointer (after casting): " + << *static_cast(void_ptr) << "\n"; // * 7. Function pointer int (*fcn_ptr)(int) = &foo; @@ -107,10 +107,10 @@ void pointers() { class CPointers : public IExample { public: - std::string group() const override { return "core"; } - std::string name() const override { return "CPointers"; } + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Pointer"; } std::string description() const override { return "Compound type: Pointers"; } void execute() override { pointers(); } }; -REGISTER_EXAMPLE(CPointers, "core", "CPointers"); +REGISTER_EXAMPLE(CPointers, "core/datatype", "Pointers"); diff --git a/src/core/datatypes/CReferences.cpp b/src/core/datatype/Reference.cpp similarity index 75% rename from src/core/datatypes/CReferences.cpp rename to src/core/datatype/Reference.cpp index 20a6583..b78b86b 100644 --- a/src/core/datatypes/CReferences.cpp +++ b/src/core/datatype/Reference.cpp @@ -1,5 +1,7 @@ +// cppcheck-suppress-file [unreadVariable] + #include -using namespace std; + // A type defined in terms of other types void increment(int& x) { @@ -17,16 +19,16 @@ int& returnRef() { } void references() { - cout << "\n--- References Type Examples ---\n"; + std::cout << "\n--- References Type Examples ---\n"; int a = 10; - cout << "a = " << a << "\n"; + std::cout << "a = " << a << "\n"; // *1. Reference basics // int &ref_error; // reference must be initialized int& ref_a = a; ref_a = 20; // modifies 'a', since ref is just an alias - cout << "ref_a =20, a = " << a << "\n"; // prints 20 + std::cout << "ref_a =20, a = " << a << "\n"; // prints 20 // Cannot reseat: once 'ref' is bound to 'a', it cannot be bound to another // variable int b = 30; ref = &b; invalid, would assign value instead of @@ -56,8 +58,7 @@ source (rvalue reference parameter, but it's the lvalue inside the function) V b */ -namespace RvalueReference { -using namespace std; +namespace rvalue_reference { // Move-like function taking an rvalue reference as parameter int copyConstructor(int&& x) { @@ -75,26 +76,28 @@ void run() { // std::move(a) casts a (lvalue) into an rvalue reference (int&&) int b = copyConstructor(std::move(a)); - cout << b << endl; // prints 100 - cout << a << endl; // prints 0, because x in the function referred to a and - // was reset + std::cout << b << std::endl; // prints 100 + std::cout + << a + << std::endl; // prints 0, because x in the function referred to a and + // was reset } -} // namespace RvalueReference +} // namespace rvalue_reference #include "ExampleRegistry.h" class CReferences : public IExample { public: - std::string group() const override { return "core"; } - std::string name() const override { return "CReferences"; } + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Reference"; } std::string description() const override { return "Compound type: References"; } void execute() override { references(); - RvalueReference::run(); + rvalue_reference::run(); } }; -REGISTER_EXAMPLE(CReferences, "core", "CReferences"); +REGISTER_EXAMPLE(CReferences, "core/datatype", "References"); diff --git a/src/core/datatypes/CStruct.cpp b/src/core/datatype/Struct.cpp similarity index 71% rename from src/core/datatypes/CStruct.cpp rename to src/core/datatype/Struct.cpp index a7f311b..5040058 100644 --- a/src/core/datatypes/CStruct.cpp +++ b/src/core/datatype/Struct.cpp @@ -1,7 +1,6 @@ #include #include -using namespace std; // A type defined in terms of other types // *0. Define a struct: @@ -13,13 +12,14 @@ struct StructDataType { double voltage{0.0}; // Default initialization int id{0}; char status{'N'}; - string label{"Unknown"}; + std::string label{"Unknown"}; /* function */ void print() const { - cout << "Size of struct = " << sizeof(StructDataType) << " bytes" << endl; - cout << "Sensor " << id << " [" << label << "] " << "Voltage: " << voltage - << " Status: " << status << endl; + std::cout << "Size of struct = " << sizeof(StructDataType) << " bytes" + << std::endl; + std::cout << "Sensor " << id << " [" << label << "] " + << "Voltage: " << voltage << " Status: " << status << std::endl; } }; @@ -33,12 +33,12 @@ void updateVoltagePtr(StructDataType* data, double newV) { data->voltage = newV; } -StructDataType makeSensor(int id, double v, const string& label) { +StructDataType makeSensor(int id, double v, const std::string& label) { return {v, id, 'N', label}; } void structs() { - cout << "\n--- Struct Type Examples ---\n"; + std::cout << "\n--- Struct Type Examples ---\n"; // *1. Using struct [[maybe_unused]] StructDataType data0; // default init StructDataType data1{3.3, 1, 'N', "Temp1"}; @@ -65,10 +65,10 @@ void structs() { class CStruct : public IExample { public: - std::string group() const override { return "core"; } - std::string name() const override { return "CStruct"; } + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Struct"; } std::string description() const override { return "Compound type: Struct"; } void execute() override { structs(); } }; -REGISTER_EXAMPLE(CStruct, "core", "CStruct"); +REGISTER_EXAMPLE(CStruct, "core/datatype", "Struct"); diff --git a/src/core/datatypes/TypeConVersions.cpp b/src/core/datatype/TypeConVersions.cpp similarity index 58% rename from src/core/datatypes/TypeConVersions.cpp rename to src/core/datatype/TypeConVersions.cpp index b41eb94..b45bfcf 100644 --- a/src/core/datatypes/TypeConVersions.cpp +++ b/src/core/datatype/TypeConVersions.cpp @@ -1,80 +1,79 @@ // cppcheck-suppress-file [unreadVariable] #include -using namespace std; class Base { public: - virtual void show() { cout << "Base class\n"; } + virtual void show() { std::cout << "Base class\n"; } virtual ~Base() = default; }; class Derived : public Base { public: - void show() override { cout << "Derived class\n"; } + void show() override { std::cout << "Derived class\n"; } }; class DerivedX : public Base { public: - void show() override { cout << "DerivedX class\n"; } + void show() override { std::cout << "DerivedX class\n"; } }; void implicitConversion() { - cout << "\n--- Implicit Type Conversion ---\n"; + std::cout << "\n--- Implicit Type Conversion ---\n"; // *1. Numeric promotion (safe, no data loss) char c = 'A'; - int i = c; // char → int - float f = 3.5f; + int i = c; // char -> int + float f = 3.5F; double d = f; // float → double bool b = true; - int b_to_int = b; // bool → int (true=1) + int b_to_int = b; // bool -> int (true=1) - cout << "char to int: " << i << "\n"; - cout << "float to double: " << d << "\n"; - cout << "bool to int: " << b_to_int << "\n"; + std::cout << "char to int: " << i << "\n"; + std::cout << "float to double: " << d << "\n"; + std::cout << "bool to int: " << b_to_int << "\n"; // *2. Numeric conversion float pi = 3.14159; double pi_double = pi; // Widening conversions int pi_int = pi; // narrowing, may lose fractional part - cout << "float to double (didening): " << pi_double << "\n"; - cout << "float to int (narrowing): " << pi_int << "\n"; + std::cout << "float to double (didening): " << pi_double << "\n"; + std::cout << "float to int (narrowing): " << pi_int << "\n"; } void explicitConversion() { - cout << "\n--- Explicit Type Conversion ---\n"; + std::cout << "\n--- Explicit Type Conversion ---\n"; double pi = 3.14159; // *1. C-style cast - not safe int pi_c = (int)pi; - cout << "C-style cast: " << pi_c << "\n"; + std::cout << "C-style cast: " << pi_c << "\n"; // **2. static_cast - type-safe relationship + compile-time type checking** int pi_static = static_cast(pi); - cout << "static_cast: " << pi_static << "\n"; + std::cout << "static_cast: " << pi_static << "\n"; // object -> object Derived derived{}; - Base baseObj = static_cast(derived); + Base base_obj = static_cast(derived); // DerivedX derivedx =static_cast(derived); // ERROR // object -> reference - const Base& baseRef = static_cast(derived); + const Base& base_ref = static_cast(derived); // object -> ptr const Base* base_ptr = static_cast(&derived); // **3. const_cast: const_cast adds or removes the const qualifier** const double c_pi = 2.71828; - const double* pConst = &c_pi; - const double* pNonConst = const_cast(pConst); // remove const - cout << "const_cast: " << *pNonConst << " (removed const)\n"; + const double* p_const = &c_pi; + const double* p_non_const = const_cast(p_const); // remove const + std::cout << "const_cast: " << *p_non_const << " (removed const)\n"; - // **4. reinterpret_cast: reinterpret memory (unsafe)** + // **4. reinterpret_cast: reinterpret memory (unssafe)** // It is used to convert a pointer of some data type into a pointer of another data type, // even if the data types before and after conversion are different. (#static,dynamic) // It does not check if the pointer type and data pointed by the pointer is same or not. - const void* pVoid = reinterpret_cast(&pi); - cout << "reinterpret_cast: address of pi = " << pVoid << "\n"; + const void* p_void = reinterpret_cast(&pi); + std::cout << "reinterpret_cast: address of pi = " << p_void << "\n"; // ******************** Use case: Memory-Mapped I/O ****************************** // C =============================================== @@ -98,24 +97,25 @@ void explicitConversion() { // Derived* derivedPtr = dynamic_cast(basePtr) // } - Base* basePtr = new Derived(); - const Derived* derivedPtr = dynamic_cast(basePtr); - if (derivedPtr) - cout << "dynamic_cast: Success (Base* -> Derived*)\n"; - else - cout << "dynamic_cast: Failed\n"; - - Base* anotherBase = new Base(); - const Derived* wrongCast = dynamic_cast(anotherBase); - if (!wrongCast) - cout << "dynamic_cast: nullptr (invalid downcast)\n"; + Base* base_ptr_2 = new Derived(); + const Derived* derived_ptr = dynamic_cast(base_ptr_2); + if (derived_ptr) { + std::cout << "dynamic_cast: Success (Base* -> Derived*)\n"; + } else { + std::cout << "dynamic_cast: Failed\n"; + } - delete basePtr; - delete anotherBase; + Base* another_base = new Base(); + const Derived* wrong_cast = dynamic_cast(another_base); + if (!wrong_cast) { + std::cout << "dynamic_cast: nullptr (invalid downcast)\n"; + } + delete base_ptr_2; + delete another_base; } void typeAliases() { - cout << "\n--- Type Aliases ---\n"; + std::cout << "\n--- Type Aliases ---\n"; // *1. using - preferred using MyDouble = double; @@ -131,7 +131,7 @@ void typeAliases() { return static_cast(x) + c; }; FuncType fptr = func; - cout << "Function pointer alias result: " << fptr(2.5, 'A') << "\n"; + std::cout << "Function pointer alias result: " << fptr(2.5, 'A') << "\n"; } int add(int x, int y) { @@ -143,30 +143,30 @@ auto add_auto(int a, int b) -> int { } void typeDeduction() { - cout << "\n--- Type Deduction ---\n"; + std::cout << "\n--- Type Deduction ---\n"; // *1. auto deduces type auto x = 42; // int auto y = 3.14; // double const auto z = x + y; // double, const ignored in type deduction - cout << "auto x: " << x << ", y: " << y << ", z: " << z << "\n"; + std::cout << "auto x: " << x << ", y: " << y << ", z: " << z << "\n"; // *2. Trailing return type - cout << "add(3,4) = " << add(3, 4) << "\n"; - cout << "add_auto(3,4) = " << add_auto(3, 4) << "\n"; + std::cout << "add(3,4) = " << add(3, 4) << "\n"; + std::cout << "add_auto(3,4) = " << add_auto(3, 4) << "\n"; // *3. std::common_type std::common_type_t val = x + y; - cout << "common_type: " << val << "\n"; + std::cout << "common_type: " << val << "\n"; } #include "ExampleRegistry.h" class CTypeConversion : public IExample { public: - std::string group() const override { return "core"; } - std::string name() const override { return "CTypeConversion"; } + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "TypeConversion"; } std::string description() const override { return ""; } void execute() override { implicitConversion(); @@ -177,4 +177,4 @@ class CTypeConversion : public IExample { } }; -REGISTER_EXAMPLE(CTypeConversion, "core", "CTypeConversion"); \ No newline at end of file +REGISTER_EXAMPLE(CTypeConversion, "core/datatype", "TypeConversion"); \ No newline at end of file diff --git a/src/core/datatypes/CUnion.cpp b/src/core/datatype/Union.cpp similarity index 86% rename from src/core/datatypes/CUnion.cpp rename to src/core/datatype/Union.cpp index 3b48c44..8e6c442 100644 --- a/src/core/datatypes/CUnion.cpp +++ b/src/core/datatype/Union.cpp @@ -24,7 +24,7 @@ void unionDemo() { std::cout << "After assigning intValue = 65:\n"; u.printAll(); // Only intValue is meaningful; others show overwritten memory - u.floatValue = 3.14f; + u.floatValue = 3.14F; std::cout << "After assigning floatValue = 3.14:\n"; u.printAll(); // Writing floatValue overwrites intValue @@ -41,10 +41,10 @@ void unionDemo() { class CUnion : public IExample { public: - std::string group() const override { return "core"; } - std::string name() const override { return "CUnion"; } + std::string group() const override { return "core/datatype"; } + std::string name() const override { return "Union"; } std::string description() const override { return "Compound type: Union"; } void execute() override { unionDemo(); } }; -REGISTER_EXAMPLE(CUnion, "core", "CUnion"); \ No newline at end of file +REGISTER_EXAMPLE(CUnion, "core/datatype", "Union"); \ No newline at end of file diff --git a/src/core/datatypes/CEnum.cpp b/src/core/datatypes/CEnum.cpp deleted file mode 100644 index c705104..0000000 --- a/src/core/datatypes/CEnum.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include // for uint8_t -#include - -using namespace std; -// A type defined in terms of other types - -// *0. Define some enums -// Unscope enum -enum BasicEnum { enumratorA, enumratorB, enumratorC }; - -// Scoped enum - enumrators are inside enum's scope -enum class ScopeEnumClass { enumratorA, enumratorB, enumratorC }; - -// Scoped enum inside a namespace -namespace EnumNameSpace { -enum class ScopeEnumClass { enumratorA, enumratorB, enumratorC }; -} - -// Scoped enum with explicit base type -enum class ScopeEnumClassB : uint8_t { - enumratorA = 0, - enumratorB = 1, - enumratorC = 2 -}; - -void enums() { - cout << "\n--- Enum Type Examples ---\n"; - // *1. Using unscope enum - [[maybe_unused]] BasicEnum unscope_e = enumratorA; - - // *2. Using scoped enum - [[maybe_unused]] ScopeEnumClass scope_e_c = ScopeEnumClass::enumratorA; - - // *3. Using scoped enum namespace - [[maybe_unused]] EnumNameSpace::ScopeEnumClass scope_e_c_n = - EnumNameSpace::ScopeEnumClass::enumratorA; - - // *4. Using scoped enum with base type - [[maybe_unused]] ScopeEnumClassB st = ScopeEnumClassB::enumratorA; -} - -#include "ExampleRegistry.h" - -class CEnum : public IExample { - public: - std::string group() const override { return "core"; } - std::string name() const override { return "CEnum"; } - std::string description() const override { return "Compound type: Enum"; } - void execute() override { enums(); } -}; - -REGISTER_EXAMPLE(CEnum, "core", "CEnum"); diff --git a/src/core/datatypes/Fundamental.cpp b/src/core/datatypes/Fundamental.cpp deleted file mode 100644 index a72c9ab..0000000 --- a/src/core/datatypes/Fundamental.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -using namespace std; - -// A basic type built into the core C++ language -void primative() { - cout << "\n--- Primative Type Examples ---\n"; - // Boolean - bool isReady = true; - cout << "bool: " << isReady << "\n"; - - // Character - char c = 'A'; - unsigned char uc = 200; - wchar_t wc = L'Ω'; // Greek Omega - // char8_t c8 = u8'A'; // UTF-8 - char16_t c16 = u'ß'; // UTF-16 - char32_t c32 = U'中'; // UTF-32 - cout << "char: " << c << "\n"; - cout << "unsigned char: " << static_cast(uc) << "\n"; - wcout << L"wchar_t: " << wc << L"\n"; - // cout << "char8_t: " << static_cast(c8) << "\n"; - cout << "char16_t: (UTF-16 code) " << static_cast(c16) << "\n"; - cout << "char32_t: (UTF-32 code) " << static_cast(c32) << "\n"; - - // Integer - short s = -10; - int i = 42; - unsigned int ui = 100; - long l = 123456L; - long long ll = 9876543210LL; - cout << "short: " << s << "\n"; - cout << "int: " << i << "\n"; - cout << "unsigned int: " << ui << "\n"; - cout << "long: " << l << "\n"; - cout << "long long: " << ll << "\n"; - - // Floating Point - float f = 3.14f; - double d = 2.718281828; - long double ld = 1.6180339887L; - cout << "float: " << f << "\n"; - cout << "double: " << d << "\n"; - cout << "long double: " << ld << "\n"; - - // Void - cout << "void: (no data type, used for functions)\n"; - - // pointer - int const* ptr = nullptr; - cout << "nullptr_t: " << ptr << "\n"; -} - -#include "ExampleRegistry.h" - -class Fundamental : public IExample { - public: - std::string group() const override { return "core"; } - std::string name() const override { return "Fundamental"; } - std::string description() const override { return "Fundamental"; } - void execute() override { primative(); } -}; - -REGISTER_EXAMPLE(Fundamental, "core", "Fundamental"); diff --git a/src/core/datetime/CTime.cpp b/src/core/datetime/Time.cpp similarity index 87% rename from src/core/datetime/CTime.cpp rename to src/core/datetime/Time.cpp index 8969c29..92abbd5 100644 --- a/src/core/datetime/CTime.cpp +++ b/src/core/datetime/Time.cpp @@ -6,7 +6,7 @@ namespace { void run() { // **1. Get the current timestamp** - std::time_t now = time(NULL); + std::time_t now = time(nullptr); const auto* ts = ctime(&now); std::cout << "Current time: " << ts << '\n'; @@ -31,9 +31,9 @@ void run() { class CTime : public IExample { public: std::string group() const override { return "core/datetime"; } - std::string name() const override { return "CTime"; } + std::string name() const override { return "Time"; } std::string description() const override { return ""; } void execute() override { run(); } }; -REGISTER_EXAMPLE(CTime, "core/datetime", "CTime"); \ No newline at end of file +REGISTER_EXAMPLE(CTime, "core/datetime", "Time"); \ No newline at end of file diff --git a/src/core/exception/BasicHandle.cpp b/src/core/exception/BasicHandle.cpp index 77410e7..ab0e423 100644 --- a/src/core/exception/BasicHandle.cpp +++ b/src/core/exception/BasicHandle.cpp @@ -12,7 +12,8 @@ void run() { errorFnc(); } catch (std::exception& e) { std::cout << e.what(); - throw std::runtime_error("[M] Middle error \n"); // use as custom exception + throw std::runtime_error( + "[M] Middle error \n"); // use as custom exception // throw; // rethrow } } catch (std::exception& e) { diff --git a/src/core/exception/README.md b/src/core/exception/README.md index 7cc4852..353894a 100644 --- a/src/core/exception/README.md +++ b/src/core/exception/README.md @@ -1,13 +1,14 @@ # Exception handling -- We prefer using exceptions with the following reasons: - - Forces the caller to recognize an error condition and handle it rather than stopping program. - - Let exceptions propagate in the call stack where they can be handled probably (e.g destroys all the objects in scope error ) - - TBD -- The exception mechanism has a minimal performance cost if no exception is thrown. If an exception is thrown, the cost of the stack traversal and unwinding is roughly comparable to the cost of a function call. +**- We prefer using exceptions with the following reasons:** + - Forces the caller to recognize an error condition and handle it rather than stopping program. + - Let exceptions propagate in the call stack where they can be handled probably (e.g destroys all the objects in scope error ) + - TBD +--- +The exception mechanism has a minimal performance cost if no exception is thrown. If an exception is thrown, the cost of the stack traversal and unwinding is roughly comparable to the cost of a function call. -- Design for exception safe: - - Low/ middle layers: catch and rethrow an exception if they do not have enough context to handle. This way, the exceptions will propagate up the call stack. - - Highest layers: let an unhandled exception terminate a program. (`exit(-1)`) - -- Resource Acquisition Is Initialization (RAII) (resource lifetime = object lifetime) +**- Design for exception safe:** + - Low/ middle layers: catch and rethrow an exception if they do not have enough context to handle. This way, the exceptions will propagate up the call stack. + - Highest layers: let an unhandled exception terminate a program. (`exit(-1)`) +--- +- *Resource Acquisition Is Initialization (RAII) (resource lifetime = object lifetime)* \ No newline at end of file diff --git a/src/core/exception/ThrowNoexcept.cpp b/src/core/exception/ThrowNoexcept.cpp index 9be8f45..8fd4a7c 100644 --- a/src/core/exception/ThrowNoexcept.cpp +++ b/src/core/exception/ThrowNoexcept.cpp @@ -7,7 +7,7 @@ void errorFnc() { throw std::runtime_error("errorFnc\n"); } -// void noExpectExcpt() throw() { +// void noExpectExcpt() throw() { // deprecated void noExpectExcpt() noexcept { try { errorFnc(); @@ -16,14 +16,14 @@ void noExpectExcpt() noexcept { } } -void expectExcpt() noexcept(false) { - try { - errorFnc(); - } catch (std::exception& e) { - std::cout << typeid(e).name() << " " << e.what(); - throw; - } -} +// void expectExcpt() noexcept(false) { +// try { +// errorFnc(); +// } catch (std::exception& e) { +// std::cout << typeid(e).name() << " " << e.what(); +// throw; +// } +// } void run() { noExpectExcpt(); diff --git a/src/core/expression/FunctionPointer.cpp b/src/core/expression/FunctionPointer.cpp index 04cdfb2..742e5a9 100644 --- a/src/core/expression/FunctionPointer.cpp +++ b/src/core/expression/FunctionPointer.cpp @@ -5,17 +5,18 @@ namespace { int increase(int a, int b) { - return a > b; + return static_cast(a > b); } int decrease(int a, int b) { - return a < b; + return static_cast(a < b); } // // Function // // Declaring // return_type (*FuncPtr) (parameter type, ....); -typedef int (*SortFcn)(int a, int b); +// typedef int (*SortFcn)(int a, int b); +using SortFcn = int (*)(int, int); void run() { std::vector vect{1, 6, 4, 22, 0, 6, 33, 39, -5}; @@ -33,15 +34,15 @@ void run() { std::cout << "Sorting in descending " << "order \n"; // Use auto - auto sortTypeAuto = increase; - std::sort(vect.begin(), vect.end(), sortTypeAuto); + auto sort_type_auto = increase; + std::sort(vect.begin(), vect.end(), sort_type_auto); // Use pointer - SortFcn sortTypePtr = decrease; + SortFcn sort_type_ptr = decrease; f_print(vect); std::cout << "Sorting with absolute " << "value as parameter\n "; - std::sort(vect.begin(), vect.end(), sortTypePtr); + std::sort(vect.begin(), vect.end(), sort_type_ptr); for (auto i : vect) std::cout << i << " "; diff --git a/src/core/filehandle/BinaryFileHandling.cpp b/src/core/filehandle/BinaryFileHandling.cpp index 3a86333..73498c8 100644 --- a/src/core/filehandle/BinaryFileHandling.cpp +++ b/src/core/filehandle/BinaryFileHandling.cpp @@ -11,48 +11,48 @@ class Account { friend std::ostream& operator<<(std::ostream&, const Account&); private: - int code; - std::string name; - double balance; + int code_; + std::string name_; + double balance_; public: - explicit Account(int c = 0, const std::string& n = "", double b = 0.0) - : code(c), name(n), balance(b) {} + explicit Account(int c = 0, std::string n = "", double b = 0.0) + : code_(c), name_(std::move(n)), balance_(b) {} - int getCode() const { return code; } + int getCode() const { return code_; } std::ostream& write(std::ostream&) const; std::istream& read(std::istream&); }; std::ostream& Account::write(std::ostream& os) const { - os.write(reinterpret_cast(&code), sizeof(code)); - os.write(reinterpret_cast(&balance), sizeof(balance)); + os.write(reinterpret_cast(&code_), sizeof(code_)); + os.write(reinterpret_cast(&balance_), sizeof(balance_)); - std::size_t length = name.size(); + std::size_t length = name_.size(); os.write(reinterpret_cast(&length), sizeof(length)); - os.write(name.data(), length); + os.write(name_.data(), length); return os; } std::istream& Account::read(std::istream& is) { - is.read(reinterpret_cast(&code), sizeof(code)); - is.read(reinterpret_cast(&balance), sizeof(balance)); + is.read(reinterpret_cast(&code_), sizeof(code_)); + is.read(reinterpret_cast(&balance_), sizeof(balance_)); std::size_t length = 0; is.read(reinterpret_cast(&length), sizeof(length)); - name.resize(length); - is.read(&name[0], length); + name_.resize(length); + is.read(name_.data(), length); return is; } std::ostream& operator<<(std::ostream& os, const Account& acc) { - os << "Code : " << acc.code << "\n"; - os << "Name : " << acc.name << "\n"; - os << "Balance: " << acc.balance << "\n"; + os << "Code : " << acc.code_ << "\n"; + os << "Name : " << acc.name_ << "\n"; + os << "Balance: " << acc.balance_ << "\n"; return os; } @@ -85,7 +85,7 @@ void run() { std::cerr << "Cannot open file for reading\n"; } else { - Account* temp = new Account(); + auto* temp = new Account(); while (inf.peek() != EOF) { temp->read(inf); diff --git a/src/core/filehandle/FileIO.cpp b/src/core/filehandle/FileIO.cpp index bfd505f..d181278 100644 --- a/src/core/filehandle/FileIO.cpp +++ b/src/core/filehandle/FileIO.cpp @@ -3,53 +3,53 @@ namespace { -constexpr inline std::string_view test_file_name = "fileio_test.csv"; +constexpr inline std::string_view kTestFileName = "fileio_test.csv"; void fileInput() { - std::ifstream inFile{std::string{test_file_name}}; - if (!inFile.is_open()) { - std::cerr << "Cannot open file: " << test_file_name << " \n"; + std::ifstream in_file{std::string{kTestFileName}}; + if (!in_file.is_open()) { + std::cerr << "Cannot open file: " << kTestFileName << " \n"; } - std::string inputStr{}; + std::string input_str{}; std::cout << "====skip while space content====" << std::endl; while ( - inFile >> - inputStr) { // Note that ifstream returns a 0 if we’ve reached the end of the file (EOF) - std::cout << inputStr; + in_file >> + input_str) { // Note that ifstream returns a 0 if we’ve reached the end of the file (EOF) + std::cout << input_str; } std::cout << "========" << std::endl; std::cout << "====full content====" << std::endl; // not skip whitespace - inFile.close(); - inFile.open(std::string{test_file_name}); // explicitly call open() + in_file.close(); + in_file.open(std::string{kTestFileName}); // explicitly call open() // The otherway to do this /** * inFile.clear(); // clear eof/fail flags * inFile.seekg(0); // rewind */ - inputStr.clear(); - while (std::getline(inFile, inputStr)) { - std::cout << inputStr << std::endl; + input_str.clear(); + while (std::getline(in_file, input_str)) { + std::cout << input_str << std::endl; } std::cout << "========" << std::endl; - inFile.close(); + in_file.close(); } void fileOutput() { std::ofstream outfile{std::string{ - test_file_name}}; // only output stream creates new file if not exist + kTestFileName}}; // only output stream creates new file if not exist if (!outfile || !outfile.is_open()) { - std::cerr << "Cannot open file: " << test_file_name << " \n"; + std::cerr << "Cannot open file: " << kTestFileName << " \n"; return; } // Put bytes data to the file // put string - std::string elfBytes{ + std::string elf_bytes{ R"""( time_s, gsr_value 0.0, 45.27761157741693 0.005, 41.69912812397066 0.01, @@ -65,33 +65,33 @@ void fileOutput() { 15.118189654760348 0.105, 15.473255351586635 0.11, 14.913896402347113 \n )"""}; - outfile << elfBytes; + outfile << elf_bytes; - elfBytes = + elf_bytes = "0x0 0x0" "0x0 0x0" "0x0 0x0"; - outfile << elfBytes; + outfile << elf_bytes; - elfBytes = + elf_bytes = "0xF 0xA \ 0xE 0xB \ 0x0 0x0"; - outfile << elfBytes; + outfile << elf_bytes; outfile.put('E'); // put char outfile.close(); } void fileRemove() { - std::remove(std::string{test_file_name}.c_str()); - std::ifstream ifile{std::string{test_file_name}}; + std::remove(std::string{kTestFileName}.c_str()); + std::ifstream ifile{std::string{kTestFileName}}; if (ifile) { - std::cerr << "Cannot delete file: " << test_file_name << " \n"; + std::cerr << "Cannot delete file: " << kTestFileName << " \n"; return; } - std::cout << "Delete file: " << test_file_name << " \n"; + std::cout << "Delete file: " << kTestFileName << " \n"; } void run() { diff --git a/src/core/filehandle/IOStream.cpp b/src/core/filehandle/IOStream.cpp index a8e78c8..4e61b33 100644 --- a/src/core/filehandle/IOStream.cpp +++ b/src/core/filehandle/IOStream.cpp @@ -10,23 +10,23 @@ void run() { // 1) input stream // input source using std::stringstream - std::string inputStr{}; + std::string input_str{}; std::stringstream input("input aa aa"); // save and redirect std::cin - auto* oldBuf = std::cin.rdbuf(input.rdbuf()); + auto* old_buf = std::cin.rdbuf(input.rdbuf()); // input from keyboard, // std::cin >> inputStr; // skip whitespace - std::getline(std::cin, inputStr); // get all + std::getline(std::cin, input_str); // get all // have to restore std::cin - std::cin.rdbuf(oldBuf); + std::cin.rdbuf(old_buf); // 2) output stream - std::cout << "[cout] " << inputStr << '\n'; - std::cerr << "[cerr] " << inputStr << '\n'; // unbuffered - std::clog << "[clog] " << inputStr << '\n'; // buffered + std::cout << "[cout] " << input_str << '\n'; + std::cerr << "[cerr] " << input_str << '\n'; // unbuffered + std::clog << "[clog] " << input_str << '\n'; // buffered } } // namespace diff --git a/src/core/filehandle/OutputFormatting.cpp b/src/core/filehandle/OutputFormatting.cpp index 399a98e..d0fd035 100644 --- a/src/core/filehandle/OutputFormatting.cpp +++ b/src/core/filehandle/OutputFormatting.cpp @@ -4,20 +4,23 @@ namespace { void run() { - std::ios oldState(nullptr); - oldState.copyfmt(std::cout); // Save state + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); // Save state // std::ios::boolalpha / noboolanpha + std::cout << "[boolalpha]\n"; std::cout << true << ' ' << false << '\n'; // 0 std::cout.setf(std::ios::boolalpha); std::cout << false << ' ' << true << '\n'; // true false // std::ios::showpos / noshowpos + std::cout << "\n[showpos]\n"; std::cout << 5 << ' ' << -5 << '\n'; // 5 -5 std::cout.setf(std::ios::boolalpha); std::cout << 5 << ' ' << -5 << '\n'; // +5 -5 // std::ios::upercase / no + std::cout << "\n[uppercase]\n"; std::cout << 12345678.9 << '\n'; // 1.23457e+07 std::cout.setf(std::ios::uppercase); std::cout << 12345678.9 << '\n'; // 1.23457E+07 @@ -26,11 +29,13 @@ void run() { // std::ios::dec // std::ios::hex // std::ios::oct + std::cout << "\n[base: dec / hex / oct]\n"; std::cout << 11 << '\n'; // 11 std::cout.setf(std::ios::hex, std::ios::basefield); std::cout << 11 << '\n'; // B // std::fixed - use dec notation + std::cout << "\n[fixed vs scientific]\n"; std::cout << std::fixed << '\n'; std::cout << std::setprecision(5) << 123.456 << '\n'; // 123.45600 @@ -39,19 +44,22 @@ void run() { std::cout << std::setprecision(5) << 123.456 << '\n'; // 1.23456e+002 // reset ======================================================== - std::cout.copyfmt(oldState); // Restore state + std::cout.copyfmt(old_state); // Restore state // std::setw() - set the filed width for input and output // std::left/right/internal - left/right justifies - Left-justifies the sign of the number, and right-justifies the value - std::cout << -12345 << '\n'; - std::cout << std::setw(10) << -12345 << '\n'; - std::cout << std::setw(10) << std::internal << -12345 << '\n'; + std::cout << "\n[width & alignment]\n"; + std::cout << "|" << -12345 << "|\n"; + std::cout << "|" << std::setw(10) << -12345 << "|\n"; // right + std::cout << "|" << std::setw(10) << std::left << -12345 << "|\n"; // left + std::cout << "|" << std::setw(10) << std::internal << -12345 << "|\n"; // internal // std::fill(char) set the fill char + std::cout << "\n[fill]\n"; std::cout.fill('*'); std::cout << std::setw(10) << std::internal << -12345 << '\n'; - std::cout.copyfmt(oldState); // Restore state + std::cout.copyfmt(old_state); // Restore state } } // namespace diff --git a/src/core/filehandle/StringStream.cpp b/src/core/filehandle/StringStream.cpp index 8eb3a12..25a0a87 100644 --- a/src/core/filehandle/StringStream.cpp +++ b/src/core/filehandle/StringStream.cpp @@ -20,13 +20,13 @@ void runStringStreamExample() { std::cout << os.str(); // output: std::ostringstream oss; - std::string bytesStr = os.str(); - std::cout << bytesStr; + std::string bytes_str = os.str(); + std::cout << bytes_str; os.str("0x0 0xF 0xE 0x2"); os.clear(); - os >> bytesStr; - std::cout << bytesStr; + os >> bytes_str; + std::cout << bytes_str; // conversions int byte_low = 0xFFF; diff --git a/src/core/overloading/AllocationOperator.cpp b/src/core/overloading/AllocationOperator.cpp index ed20907..be3aa27 100644 --- a/src/core/overloading/AllocationOperator.cpp +++ b/src/core/overloading/AllocationOperator.cpp @@ -9,32 +9,32 @@ namespace { class IntCollection { private: - int m_data[3]{10, 20, 30}; + int m_data_[3]{10, 20, 30}; public: class Iterator { private: - int* m_ptr; + int* m_ptr_; public: - explicit Iterator(int* ptr) : m_ptr(ptr) {} + explicit Iterator(int* ptr) : m_ptr_(ptr) {} - int& operator*() { return *m_ptr; } + int& operator*() { return *m_ptr_; } - int* operator->() { return m_ptr; } + int* operator->() { return m_ptr_; } Iterator& operator++() { - ++m_ptr; + ++m_ptr_; return *this; } bool operator!=(const Iterator& other) const { - return m_ptr != other.m_ptr; + return m_ptr_ != other.m_ptr_; } }; - Iterator begin() { return Iterator(m_data); } - Iterator end() { return Iterator(m_data + 3); } + Iterator begin() { return Iterator(m_data_); } + Iterator end() { return Iterator(m_data_ + 3); } // int* a = new int; void* operator new(size_t size) { @@ -69,7 +69,7 @@ class IntCollection { }; void run() { - IntCollection* col = new IntCollection; + auto* col = new IntCollection; for (auto it = col->begin(); it != col->end(); ++it) { std::cout << *it << '\n'; @@ -77,7 +77,7 @@ void run() { delete col; - IntCollection* cols = new IntCollection[10]; + auto* cols = new IntCollection[10]; for (int i = 0; i < 10; ++i) { for (auto it = cols[i].begin(); it != cols[i].end(); ++it) { std::cout << *it << '\n'; diff --git a/src/core/overloading/ArithmeticOperator.cpp b/src/core/overloading/ArithmeticOperator.cpp index 0506024..023c310 100644 --- a/src/core/overloading/ArithmeticOperator.cpp +++ b/src/core/overloading/ArithmeticOperator.cpp @@ -6,11 +6,11 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents) : m_cents{cents} {} - int getCents() const { return m_cents; } + explicit Cents(int cents) : m_cents_{cents} {} + int getCents() const { return m_cents_; } // Problem: A member operator only works when the left-hand operand is an object of the class (e.g., Cents). // Cents sum = 5 + s1; diff --git a/src/core/overloading/AssignmentOperator.cpp b/src/core/overloading/AssignmentOperator.cpp index f5a4fad..b01128b 100644 --- a/src/core/overloading/AssignmentOperator.cpp +++ b/src/core/overloading/AssignmentOperator.cpp @@ -8,25 +8,25 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents = 0) : m_cents{cents} {} + explicit Cents(int cents = 0) : m_cents_{cents} {} - int getCents() const { return m_cents; } - void setCents(int cents) { m_cents = cents; } + int getCents() const { return m_cents_; } + void setCents(int cents) { m_cents_ = cents; } // Copy constructor Cents(const Cents& other) { std::cout << "Cents(const Cents& other)\n"; - m_cents = other.m_cents; + m_cents_ = other.m_cents_; } // Overload copy assignment Cents& operator=(const Cents& cents) { // do the copy std::cout << "Cents& operator=(const Cents& cents)\n"; - m_cents = cents.m_cents; + m_cents_ = cents.m_cents_; return *this; } }; diff --git a/src/core/overloading/ClassMemberAccessOperator.cpp b/src/core/overloading/ClassMemberAccessOperator.cpp index 130b43f..b3d418e 100644 --- a/src/core/overloading/ClassMemberAccessOperator.cpp +++ b/src/core/overloading/ClassMemberAccessOperator.cpp @@ -9,38 +9,38 @@ namespace { class IntCollection { private: - int m_data[3]{10, 20, 30}; + int m_data_[3]{10, 20, 30}; public: class Iterator { private: - int* m_ptr; + int* m_ptr_; public: - explicit Iterator(int* ptr) : m_ptr(ptr) {} + explicit Iterator(int* ptr) : m_ptr_(ptr) {} int& operator*() { std::cout << "int& operator*()\n"; - return *m_ptr; + return *m_ptr_; } int* operator->() { std::cout << "int* operator->()\n"; - return m_ptr; + return m_ptr_; } Iterator& operator++() { - ++m_ptr; + ++m_ptr_; return *this; } bool operator!=(const Iterator& other) const { - return m_ptr != other.m_ptr; + return m_ptr_ != other.m_ptr_; } }; - Iterator begin() { return Iterator(m_data); } - Iterator end() { return Iterator(m_data + 3); } + Iterator begin() { return Iterator(m_data_); } + Iterator end() { return Iterator(m_data_ + 3); } }; void run() { diff --git a/src/core/overloading/ComparisonOperator.cpp b/src/core/overloading/ComparisonOperator.cpp index ff6c68e..9a2dada 100644 --- a/src/core/overloading/ComparisonOperator.cpp +++ b/src/core/overloading/ComparisonOperator.cpp @@ -6,11 +6,11 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents) : m_cents{cents} {} - int getCents() const { return m_cents; } + explicit Cents(int cents) : m_cents_{cents} {} + int getCents() const { return m_cents_; } auto operator<=> (const Cents&) const = default; // std 20 // friend bool operator== (const Cents& c1, const Cents& c2) { return c1.m_cents == c2.m_cents; } diff --git a/src/core/overloading/IOOperator.cpp b/src/core/overloading/IOOperator.cpp index 3b1c42f..004cca8 100644 --- a/src/core/overloading/IOOperator.cpp +++ b/src/core/overloading/IOOperator.cpp @@ -7,11 +7,11 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents) : m_cents{cents} {} - int getCents() const { return m_cents; } + explicit Cents(int cents) : m_cents_{cents} {} + int getCents() const { return m_cents_; } // // We won’t be able to use a member overload if the left operand is either not a class (e.g. int), // // or it is a class that we can’t modify (e.g. std::ostream). diff --git a/src/core/overloading/InDecOperator.cpp b/src/core/overloading/InDecOperator.cpp index fb68573..b2a0a1a 100644 --- a/src/core/overloading/InDecOperator.cpp +++ b/src/core/overloading/InDecOperator.cpp @@ -7,11 +7,11 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents) : m_cents{cents} {} - int getCents() const { return m_cents; } + explicit Cents(int cents) : m_cents_{cents} {} + int getCents() const { return m_cents_; } // pre: inc -> return new Cents& operator++(); @@ -24,11 +24,11 @@ class Cents { // pre ++x/--x Cents& Cents::operator++() { - ++m_cents; + ++m_cents_; return *this; } Cents& Cents::operator--() { - --m_cents; + --m_cents_; return *this; } diff --git a/src/core/overloading/ParenthesisOperator.cpp b/src/core/overloading/ParenthesisOperator.cpp index ec8f1c3..bfa3ec9 100644 --- a/src/core/overloading/ParenthesisOperator.cpp +++ b/src/core/overloading/ParenthesisOperator.cpp @@ -9,7 +9,7 @@ namespace { class Matrix { private: - double m_data[4][4]{}; + double m_data_[4][4]{}; public: double& operator()(int row, int col); @@ -20,14 +20,14 @@ double& Matrix::operator()(int row, int col) { assert(row >= 0 && row < 4); assert(col >= 0 && col < 4); - return m_data[row][col]; + return m_data_[row][col]; } double Matrix::operator()(int row, int col) const { assert(row >= 0 && row < 4); assert(col >= 0 && col < 4); - return m_data[row][col]; + return m_data_[row][col]; } void run() { diff --git a/src/core/overloading/SubscriptOperator.cpp b/src/core/overloading/SubscriptOperator.cpp index a1896c1..99fa7ea 100644 --- a/src/core/overloading/SubscriptOperator.cpp +++ b/src/core/overloading/SubscriptOperator.cpp @@ -8,17 +8,17 @@ namespace { class IntList { private: - int m_list[10]{ + int m_list_[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // give this class some initial state for this example public: // For non-const objects: can be used for assignment - int& operator[](int index) { return m_list[index]; } + int& operator[](int index) { return m_list_[index]; } // For const objects: can only be used for access // This function could also return by value if the type is cheap to copy - const int& operator[](int index) const { return m_list[index]; } + const int& operator[](int index) const { return m_list_[index]; } }; void run() { diff --git a/src/core/overloading/TypeCast.cpp b/src/core/overloading/TypeCast.cpp index ce8fa35..a3bcb75 100644 --- a/src/core/overloading/TypeCast.cpp +++ b/src/core/overloading/TypeCast.cpp @@ -8,34 +8,34 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents = 0) : m_cents{cents} {} + explicit Cents(int cents = 0) : m_cents_{cents} {} // note that there is a space between operator keyword and the type we are casting // overloading explicit cast operator explicit operator int() const { std::cout << "explicit operator int() const\n"; - return m_cents; + return m_cents_; } - int getCents() const { return m_cents; } - void setCents(int cents) { m_cents = cents; } + int getCents() const { return m_cents_; } + void setCents(int cents) { m_cents_ = cents; } }; class Dollars { private: - int m_dollars{}; + int m_dollars_{}; public: // overloading non-explicit cast operator operator Cents() const { std::cout << "operator Cents() const\n"; - return Cents{m_dollars * 1000}; + return Cents{m_dollars_ * 1000}; } - explicit Dollars(int dollars = 0) : m_dollars{dollars} {} + explicit Dollars(int dollars = 0) : m_dollars_{dollars} {} }; void printCents(Cents c) { diff --git a/src/core/overloading/UnaryOperator.cpp b/src/core/overloading/UnaryOperator.cpp index 4321586..3853cb5 100644 --- a/src/core/overloading/UnaryOperator.cpp +++ b/src/core/overloading/UnaryOperator.cpp @@ -7,17 +7,17 @@ namespace { class Cents { private: - int m_cents{}; + int m_cents_{}; public: - explicit Cents(int cents) : m_cents{cents} {} - int getCents() const { return m_cents; } + explicit Cents(int cents) : m_cents_{cents} {} + int getCents() const { return m_cents_; } - Cents operator-() const { return Cents{-m_cents}; } + Cents operator-() const { return Cents{-m_cents_}; } - Cents operator+() const { return Cents{m_cents}; } + Cents operator+() const { return Cents{m_cents_}; } - bool operator!() const { return m_cents == 0; } + bool operator!() const { return m_cents_ == 0; } }; void run() { diff --git a/src/core/smart_pointer/Shared.cpp b/src/core/smart_pointer/Shared.cpp index 48dc723..68e22a5 100644 --- a/src/core/smart_pointer/Shared.cpp +++ b/src/core/smart_pointer/Shared.cpp @@ -20,30 +20,30 @@ struct AppConfig { class NetworkManager { public: explicit NetworkManager(std::shared_ptr cfg) - : mConfig(std::move(cfg)) {} + : config_(std::move(cfg)) {} void connect() const { - std::cout << "Connecting to " << mConfig->server << ":" << mConfig->port + std::cout << "Connecting to " << config_->server << ":" << config_->port << "\n"; } private: // const means we cannot modify config at this point - std::shared_ptr mConfig; + std::shared_ptr config_; }; // Module B class Logger { public: explicit Logger(std::shared_ptr cfg) - : mConfig(std::move(cfg)) {} + : config_(std::move(cfg)) {} void log_start() const { - std::cout << "Logging enabled for " << mConfig->server << "\n"; + std::cout << "Logging enabled for " << config_->server << "\n"; } private: - std::shared_ptr mConfig; + std::shared_ptr config_; }; void run() { @@ -69,10 +69,10 @@ void run() { class Shared : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/smart_pointer"; } std::string name() const override { return "Shared"; } std::string description() const override { return "Shared Pointer Example"; } void execute() override { run(); } }; -REGISTER_EXAMPLE(Shared, "core", "Shared"); \ No newline at end of file +REGISTER_EXAMPLE(Shared, "core/smart_pointer", "Shared"); \ No newline at end of file diff --git a/src/core/smart_pointer/Unique.cpp b/src/core/smart_pointer/Unique.cpp index 514b6b6..4d2132a 100644 --- a/src/core/smart_pointer/Unique.cpp +++ b/src/core/smart_pointer/Unique.cpp @@ -5,14 +5,14 @@ namespace { class Model { private: - std::unique_ptr cstring; + std::unique_ptr cstring_; public: - explicit Model(const char* s) : cstring{nullptr} { + explicit Model(const char* s) : cstring_{nullptr} { if (s) { // allocate - cstring = std::make_unique(std::strlen(s) + 1); - std::strcpy(cstring.get(), s); // populate + cstring_ = std::make_unique(std::strlen(s) + 1); + std::strcpy(cstring_.get(), s); // populate } } @@ -20,12 +20,12 @@ class Model { // Helper functions const char* c_str() const // accessor { - return cstring.get(); + return cstring_.get(); } void set_first_char(char ch) { - if (cstring) - cstring[0] = ch; + if (cstring_) + cstring_[0] = ch; } }; @@ -57,10 +57,10 @@ void run() { class Unique : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/smart_pointer"; } std::string name() const override { return "Unique"; } std::string description() const override { return "Unique Pointer Example"; } void execute() override { run(); } }; -REGISTER_EXAMPLE(Unique, "core", "Unique"); \ No newline at end of file +REGISTER_EXAMPLE(Unique, "core/smart_pointer", "Unique"); \ No newline at end of file diff --git a/src/core/smart_pointer/Weak.cpp b/src/core/smart_pointer/Weak.cpp index 3204bed..e3bf824 100644 --- a/src/core/smart_pointer/Weak.cpp +++ b/src/core/smart_pointer/Weak.cpp @@ -17,24 +17,24 @@ struct AppConfig { }; void run() { - std::weak_ptr observeConfig; + std::weak_ptr observe_config; { std::shared_ptr config = std::make_shared("test.server.com", 80); // check lock() to determine if pointer is valid - observeConfig = config; - if (auto tmpConfig = observeConfig.lock()) { - std::cout << "[O] config value is: " << tmpConfig->port << " " - << tmpConfig->server << '\n'; + observe_config = config; + if (auto tmp_config = observe_config.lock()) { + std::cout << "[O] config value is: " << tmp_config->port << " " + << tmp_config->server << '\n'; } else { std::cout << "[O] config is expired\n"; } } - if (auto tmpConfig = observeConfig.lock()) { - std::cout << "[O] config value is: " << tmpConfig->port << " " - << tmpConfig->server << '\n'; + if (auto tmp_config = observe_config.lock()) { + std::cout << "[O] config value is: " << tmp_config->port << " " + << tmp_config->server << '\n'; } else { std::cout << "[O] config is expired\n"; } @@ -50,10 +50,10 @@ void run() { class Weak : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/smart_pointer"; } std::string name() const override { return "Weak"; } std::string description() const override { return "Weak Pointer Example"; } void execute() override { run(); } }; -REGISTER_EXAMPLE(Weak, "core", "Weak"); \ No newline at end of file +REGISTER_EXAMPLE(Weak, "core/smart_pointer", "Weak"); \ No newline at end of file diff --git a/src/core/string/BasicString.cpp b/src/core/string/CString.cpp similarity index 68% rename from src/core/string/BasicString.cpp rename to src/core/string/CString.cpp index 7a968a3..cfddc69 100644 --- a/src/core/string/BasicString.cpp +++ b/src/core/string/CString.cpp @@ -1,9 +1,9 @@ -#include // C-String +#include // C-String #include namespace { -namespace InitializeString { +namespace initialize_string { // Memory layout (addresses are illustrative): // Stack (modifiable array) @@ -28,37 +28,37 @@ namespace InitializeString { // 0x7fffbff0: str1 = 0x00403000 // str1 holds address of string literal void run() { // **1. As a character array (modifiable)** - char strArray[] = "this is a strArray literal"; - std::cout << strArray << " - size " << sizeof(strArray) << " - length " - << strlen(strArray) << "\n"; - strArray[0] ^= ' '; - std::cout << strArray << "\n"; + char str_array[] = "this is a strArray literal"; + std::cout << str_array << " - size " << sizeof(str_array) << " - length " + << strlen(str_array) << "\n"; + str_array[0] ^= ' '; + std::cout << str_array << "\n"; // **2. As a a pointer to a string literal const (read-only)** // Literal is const char* - char* strPtr = "this is a strPtr literal"; - std::cout << strPtr << " - size " << sizeof(strPtr) << " - length " - << strlen(strPtr) << "\n"; + char* str_ptr = "this is a strPtr literal"; + std::cout << str_ptr << " - size " << sizeof(str_ptr) << " - length " + << strlen(str_ptr) << "\n"; // strPtr[0] ^= ' '; // ERROR // **3. Using sprintf / snprintf (string formatting)** - char strFormatted[50]; - int numVar = 21; + char str_formatted[50]; + int num_var = 21; // sprintf (unsafe if buffer too small) - sprintf(strFormatted, "sprintf: %d", numVar); - std::cout << strFormatted << " - size " << sizeof(strFormatted) - << " - length " << strlen(strFormatted) << "\n"; + sprintf(str_formatted, "sprintf: %d", num_var); + std::cout << str_formatted << " - size " << sizeof(str_formatted) + << " - length " << strlen(str_formatted) << "\n"; // snprintf (safer, limits buffer size) - snprintf(strFormatted, sizeof(strFormatted), "snprintf %s %d", strArray, - numVar); - std::cout << strFormatted << " - size " << sizeof(strFormatted) - << " - length " << strlen(strFormatted) << "\n"; + snprintf(str_formatted, sizeof(str_formatted), "snprintf %s %d", str_array, + num_var); + std::cout << str_formatted << " - size " << sizeof(str_formatted) + << " - length " << strlen(str_formatted) << "\n"; } -} // namespace InitializeString +} // namespace initialize_string -namespace CopyString { +namespace copy_string { void run() { const char src[] = "CopyStr"; char dst[50]; @@ -76,9 +76,9 @@ void run() { std::cout << dst << " - size " << sizeof(dst) << " - length " << strlen(dst) << "\n"; } -} // namespace CopyString +} // namespace copy_string -namespace ConcatString { +namespace concat_string { void run() { const char part1[] = "Hello"; const char part2[] = "World"; @@ -96,9 +96,9 @@ void run() { std::cout << dst << " - size " << sizeof(dst) << " - length " << strlen(dst) << "\n"; } -} // namespace ConcatString +} // namespace concat_string -namespace CompareString { +namespace compare_string { void run() { const char str1[] = "abc"; const char str2[] = "abcde"; @@ -117,9 +117,9 @@ void run() { int result3 = strncmp(str1, str2, 3); std::cout << "strncmp(str1, str2, 3) = " << result3 << "\n"; } -} // namespace CompareString +} // namespace compare_string -namespace ParseString { +namespace parse_string { void run() { char str[] = "A,B,C,D,"; // OK // char* str = "A,B,C,D,"; // ERROR - const @@ -130,7 +130,7 @@ void run() { const char* token = strtok(str, delimiter); while (token != nullptr) { std::cout << "strtok - token :" << token << "\n"; - token = strtok(NULL, delimiter); + token = strtok(nullptr, delimiter); } { std::cout << " === problem === \n"; @@ -157,7 +157,7 @@ void run() { const char* token2 = strtok_r(str2, delimiter, &saveptr); while (token2 != nullptr) { std::cout << "strtok - token :" << token2 << "\n"; - token2 = strtok_r(NULL, delimiter, &saveptr); + token2 = strtok_r(nullptr, delimiter, &saveptr); } // **2. strcspn: find first occurrence of any chars in reject set** @@ -169,43 +169,43 @@ void run() { << "\n"; std::cout << "The digit is: " << sample[pos] << "\n"; } -} // namespace ParseString +} // namespace parse_string -namespace NumberConversion { +namespace number_conversion { void run() { // **1. string to integer** - const char strNum[] = "100"; - int num = atoi(strNum); + const char str_num[] = "100"; + int num = atoi(str_num); std::cout << num << "\n"; // **2. string to double** - const char strNumD[] = "100.1234__123"; - double numD = atof(strNumD); - std::cout << numD << "\n"; + const char str_num_d[] = "100.1234__123"; + double num_d = atof(str_num_d); + std::cout << num_d << "\n"; char* end; - numD = strtod(strNumD, &end); - std::cout << numD << " end part:" << end << "\n"; + num_d = strtod(str_num_d, &end); + std::cout << num_d << " end part:" << end << "\n"; } -} // namespace NumberConversion +} // namespace number_conversion } // namespace #include "ExampleRegistry.h" -class BasicString : public IExample { +class CString : public IExample { public: std::string group() const override { return "core/string"; } - std::string name() const override { return "BasicString"; } - std::string description() const override { return "String Example"; } + std::string name() const override { return "C-String"; } + std::string description() const override { return "C-String Example"; } void execute() override { - InitializeString::run(); - CopyString::run(); - ConcatString::run(); - CompareString::run(); - ParseString::run(); + initialize_string::run(); + copy_string::run(); + concat_string::run(); + compare_string::run(); + parse_string::run(); - NumberConversion::run(); + number_conversion::run(); } }; -REGISTER_EXAMPLE(BasicString, "core/string", "BasicString"); +REGISTER_EXAMPLE(CString, "core/string", "C-String"); diff --git a/src/core/string/StdString.cpp b/src/core/string/StdString.cpp index 9853701..9e88dc8 100644 --- a/src/core/string/StdString.cpp +++ b/src/core/string/StdString.cpp @@ -4,7 +4,7 @@ #include #include "ExampleRegistry.h" -namespace Create { +namespace create { void run() { // 1. Direct initialization with literal std::string s1 = "string 1"; @@ -30,9 +30,9 @@ void run() { std::cout << "s4: " << s4 << '\n'; std::cout << "s5: " << s5 << '\n'; } -} // namespace Create +} // namespace create -namespace Modify { +namespace modify { void run() { std::string ss = "xPhong"; std::cout << "init : " << ss << '\n'; @@ -72,18 +72,18 @@ void run() { ss.erase(ss.find_last_not_of(" \t\n\r") + 1); std::cout << "trim last : " << ss << '\n'; } -} // namespace Modify +} // namespace modify -namespace Sub { +namespace sub { void run() { std::string ss = "PhongNguyen"; std::cout << "init : " << ss << '\n'; - std::string firstName = ss.substr(0, 5); - std::cout << "sub : " << firstName << '\n'; + std::string first_name = ss.substr(0, 5); + std::cout << "sub : " << first_name << '\n'; } -} // namespace Sub +} // namespace sub -namespace Search { +namespace search { void run() { std::string ss = "PhongNguyen"; std::cout << "init : " << ss << '\n'; @@ -91,8 +91,8 @@ void run() { // find char size_t pos = ss.find('N'); if (pos != std::string::npos) { - std::string secondName = ss.substr(pos); // from pos to end (default) - std::cout << "find 'N' : at " << pos << " -> " << secondName << '\n'; + std::string second_name = ss.substr(pos); // from pos to end (default) + std::cout << "find 'N' : at " << pos << " -> " << second_name << '\n'; } // find substring @@ -107,9 +107,9 @@ void run() { std::cout << "rfind 'n' : at " << pos << '\n'; } } -} // namespace Search +} // namespace search -namespace Compare { +namespace compare { void run() { std::string ss1 = "PhongNguyen"; std::string ss2 = "PhongNguyen"; @@ -120,9 +120,9 @@ void run() { std::cout << "equal ? : " << std::boolalpha << (result == 0) << '\n'; } -} // namespace Compare +} // namespace compare -namespace Convert { +namespace convert { void run() { // string -> int std::string sint = "3"; @@ -139,9 +139,9 @@ void run() { std::string svalue = std::to_string(value); std::cout << "to_string : " << svalue << '\n'; } -} // namespace Convert +} // namespace convert -namespace Parsing { +namespace parsing { void run() { std::string line = "a,b,c"; std::cout << "init : " << line << '\n'; @@ -154,7 +154,7 @@ void run() { std::cout << item << std::endl; } } -} // namespace Parsing +} // namespace parsing class StdString : public IExample { public: @@ -162,13 +162,13 @@ class StdString : public IExample { std::string name() const override { return "StdString"; } std::string description() const override { return "StdString Example"; } void execute() override { - Create::run(); - Modify::run(); - Sub::run(); - Search::run(); - Compare::run(); - Convert::run(); - Parsing::run(); + create::run(); + modify::run(); + sub::run(); + search::run(); + compare::run(); + convert::run(); + parsing::run(); } }; diff --git a/src/core/string/StringFormatting.cpp b/src/core/string/StringFormatting.cpp index 0b0ca1c..2f37a13 100644 --- a/src/core/string/StringFormatting.cpp +++ b/src/core/string/StringFormatting.cpp @@ -6,7 +6,7 @@ #include "ExampleRegistry.h" -namespace StdFormat { +namespace std_format { void run() { std::string name{"Phong"}; int score = 100; @@ -16,9 +16,9 @@ void run() { std::cout << s; } -} // namespace StdFormat +} // namespace std_format -namespace Concatenation { +namespace concatenation { void run() { std::string name{"Phong"}; int score = 100; @@ -28,9 +28,9 @@ void run() { std::cout << s; } -} // namespace Concatenation +} // namespace concatenation -namespace Stream { +namespace stream { void run() { std::string name{"Phong"}; int score = 100; @@ -41,9 +41,9 @@ void run() { std::cout << ss.str(); } -} // namespace Stream +} // namespace stream -namespace CStyle { +namespace c_style { void run() { std::string name{"Phong"}; int score = 100; @@ -54,7 +54,7 @@ void run() { std::cout << buffer; } -} // namespace CStyle +} // namespace c_style class StringFormatting : public IExample { public: @@ -68,10 +68,10 @@ class StringFormatting : public IExample { } void execute() override { - StdFormat::run(); - Concatenation::run(); - Stream::run(); - CStyle::run(); + std_format::run(); + concatenation::run(); + stream::run(); + c_style::run(); } }; diff --git a/src/core/utils/StdAlgorithm.cpp b/src/core/utils/StdAlgorithm.cpp index b4eaf10..aea60d7 100644 --- a/src/core/utils/StdAlgorithm.cpp +++ b/src/core/utils/StdAlgorithm.cpp @@ -3,7 +3,7 @@ #include "ExampleRegistry.h" -namespace FindIfExample { +namespace find_if_example { void run() { std::cout << "std::find_if example\n"; std::vector v{1, 2, 3, 4, 5}; @@ -32,7 +32,7 @@ class StdAlgorithm : public IExample { return "The examples for header"; } - void execute() override { FindIfExample::run(); } + void execute() override { find_if_example::run(); } }; REGISTER_EXAMPLE(StdAlgorithm, "core/utils", "StdAlgorithm"); \ No newline at end of file diff --git a/src/dp/behavioral/ChainOfCommand.cpp b/src/dp/behavioral/ChainOfCommand.cpp index 4a9ee52..44cd9f6 100644 --- a/src/dp/behavioral/ChainOfCommand.cpp +++ b/src/dp/behavioral/ChainOfCommand.cpp @@ -9,17 +9,17 @@ // UML: docs/uml/patterns_behavioral_CoR.drawio.svg -#include #include -#include +#include "Logger.h" namespace { -namespace CoR { +namespace co_r { /* * Handler - defines an interface for handling requests */ class IHandler { public: + virtual ~IHandler() = default; virtual void setNextHandler(IHandler* handler) = 0; virtual IHandler* setNext(IHandler* handler) = 0; virtual void handle(const std::string& request) = 0; @@ -27,24 +27,24 @@ class IHandler { class AbstractHandler : public IHandler { private: - IHandler* m_setNext; + IHandler* setNext_{}; public: - AbstractHandler() : m_setNext{nullptr} {}; + AbstractHandler() = default; - void setNextHandler(IHandler* handler) override { this->m_setNext = handler; } + void setNextHandler(IHandler* handler) override { this->setNext_ = handler; } // handler1->setNext(handler2)->setNext(handler3) IHandler* setNext(IHandler* handler) override { - this->m_setNext = handler; + this->setNext_ = handler; return handler; } void handle(const std::string& request) override { - if (this->m_setNext != nullptr) { - this->m_setNext->handle(request); + if (this->setNext_ != nullptr) { + this->setNext_->handle(request); } else { - std::cout << "\tNo handler processed request: " << request << "\n"; + LOG("\tNo handler processed request: " + request); } } }; @@ -56,13 +56,13 @@ class AbstractHandler : public IHandler { */ class ConcreteHandlerGET : public AbstractHandler { private: - static constexpr const char* header = "GET"; + static constexpr const char* kHeader = "GET"; public: void handle(const std::string& request) override { - if (request.rfind(header, 0) == 0) { + if (request.rfind(kHeader, 0) == 0) { // If request is eligible, handle it - std::cout << "\tHandle GET request: " << request << "\n"; + LOG("\tHandle GET request: " + request); // In realworld, it should be other logics here } else { AbstractHandler::handle(request); @@ -72,12 +72,12 @@ class ConcreteHandlerGET : public AbstractHandler { class ConcreteHandlerPUT : public AbstractHandler { private: - static constexpr const char* header = "PUT"; + static constexpr const char* kHeader = "PUT"; public: void handle(const std::string& request) override { - if (request.rfind(header, 0) == 0) { - std::cout << "\tHandle PUT request: " << request << "\n"; + if (request.rfind(kHeader, 0) == 0) { + LOG("\tHandle PUT request: " + request); } else { AbstractHandler::handle(request); } @@ -86,12 +86,12 @@ class ConcreteHandlerPUT : public AbstractHandler { class ConcreteHandlerPOST : public AbstractHandler { private: - static constexpr const char* header = "POST"; + static constexpr const char* kHeader = "POST"; public: void handle(const std::string& request) override { - if (request.rfind(header, 0) == 0) { - std::cout << "\tHandle POST request: " << request << "\n"; + if (request.rfind(kHeader, 0) == 0) { + LOG("\tHandle POST request: " + request); } else { AbstractHandler::handle(request); } @@ -102,35 +102,35 @@ class ConcreteHandlerPOST : public AbstractHandler { * Client - sends commands to the first object in the chain that may handle the * command */ -namespace Client { +namespace client { void clientCode(IHandler& handler, const std::string& request) { handler.handle(request); } -} // namespace Client +} // namespace client void run() { // Setup Chain of Responsibility - IHandler* postHandler = new ConcreteHandlerPOST(); - IHandler* gettHandler = new ConcreteHandlerGET(); - IHandler* puttHandler = new ConcreteHandlerPUT(); - postHandler->setNext(gettHandler)->setNext(puttHandler); + IHandler* post_handler = new ConcreteHandlerPOST(); + IHandler* gett_handler = new ConcreteHandlerGET(); + IHandler* putt_handler = new ConcreteHandlerPUT(); + post_handler->setNext(gett_handler)->setNext(putt_handler); // Send requests to the chain std::string dummy = "DUMMY .."; - std::string postRequest = "POST /test/demo_form.php HTTP/1.1 .."; - std::string getRequest = "GET /users/123 .."; - std::cout << "Send dummy request\n"; - Client::clientCode(*postHandler, dummy); - std::cout << "Send POST request\n"; - Client::clientCode(*postHandler, postRequest); - std::cout << "Send GET request\n"; - Client::clientCode(*postHandler, getRequest); - - delete postHandler; - delete gettHandler; - delete puttHandler; + std::string post_request = "POST /test/demo_form.php HTTP/1.1 .."; + std::string get_request = "GET /users/123 .."; + LOG("Send dummy request"); + client::clientCode(*post_handler, dummy); + LOG("Send POST request"); + client::clientCode(*post_handler, post_request); + LOG("Send GET request"); + client::clientCode(*post_handler, get_request); + + delete post_handler; + delete gett_handler; + delete putt_handler; } -} // namespace CoR +} // namespace co_r } // namespace @@ -141,7 +141,7 @@ class ChainOfResponsibilityExample : public IExample { std::string group() const override { return "dp/behavioral"; } std::string name() const override { return "ChainOfResponsibility"; } std::string description() const override { return "CoR Pattern Example"; } - void execute() override { CoR::run(); } + void execute() override { co_r::run(); } }; REGISTER_EXAMPLE(ChainOfResponsibilityExample, "dp/behavioral", diff --git a/src/dp/behavioral/Command.cpp b/src/dp/behavioral/Command.cpp index 4136e8a..9b240c8 100644 --- a/src/dp/behavioral/Command.cpp +++ b/src/dp/behavioral/Command.cpp @@ -13,9 +13,10 @@ #include #include +#include namespace { -namespace Command { +namespace command { /** * The Command interface usually declares just a single method for executing the @@ -23,6 +24,7 @@ namespace Command { */ class ICommand { public: + virtual ~ICommand() = default; virtual void execute() const = 0; }; @@ -34,11 +36,23 @@ class ICommand { */ class Receiver { public: - static void doCheck() { std::cout << "Receiver checking... \n"; }; - static void doInit() { std::cout << "Receiver initializing... \n"; }; - static void doLaunch(const std::string& arg) { + void doCheck() { + std::cout << "Receiver checking... \n"; + dummy_++; + }; + + void doInit() { + std::cout << "Receiver initializing... \n"; + dummy_++; + }; + + void doLaunch(const std::string& arg) { std::cout << "Receiver launching... \n\t" << arg << "\n"; + dummy_++; }; + + private: + int dummy_{}; }; /** @@ -54,18 +68,18 @@ class SimpleConcreteCommand : public ICommand { class ComplexConcreteCommand : public ICommand { private: - Receiver* m_receiver; - std::string m_payload; + Receiver* receiver_; + std::string payload_; public: - ComplexConcreteCommand(Receiver* receiver, const std::string& payload) - : m_receiver{receiver}, m_payload{payload} {}; + ComplexConcreteCommand(Receiver* receiver, std::string payload) + : receiver_{receiver}, payload_{std::move(payload)} {}; void execute() const override { std::cout << "\t ComplexCommand executed \n"; - this->m_receiver->doCheck(); - this->m_receiver->doInit(); - this->m_receiver->doLaunch(m_payload); + this->receiver_->doCheck(); + this->receiver_->doInit(); + this->receiver_->doLaunch(payload_); } }; @@ -79,50 +93,49 @@ class ComplexConcreteCommand : public ICommand { */ class Invoker { private: - ICommand* m_on_start; - ICommand* m_on_finish; + ICommand* on_start_; + ICommand* on_finish_; public: - explicit Invoker(ICommand* s = nullptr, ICommand* f = nullptr) - : m_on_start{s}, m_on_finish{s} {} + explicit Invoker(ICommand* s = nullptr) : on_start_{s}, on_finish_{s} {} ~Invoker() { - delete m_on_start; - delete m_on_finish; + delete on_start_; + delete on_finish_; } - void setOnStart(ICommand* command) { this->m_on_start = command; } + void setOnStart(ICommand* command) { this->on_start_ = command; } - void setOnFinish(ICommand* command) { this->m_on_finish = command; } + void setOnFinish(ICommand* command) { this->on_finish_ = command; } void invoke() const { - if (m_on_start != nullptr) { - m_on_start->execute(); + if (on_start_ != nullptr) { + on_start_->execute(); } - if (m_on_finish != nullptr) { - m_on_finish->execute(); + if (on_finish_ != nullptr) { + on_finish_->execute(); } } }; -namespace Client { +namespace client { void clientCode(const Invoker* invoker) { invoker->invoke(); } -} // namespace Client +} // namespace client void run() { - Receiver* ui = new Receiver(); + auto* ui = new Receiver(); // How to execute these command when something triggered - Invoker* invoker = new Invoker(); + auto* invoker = new Invoker(); invoker->setOnStart(new SimpleConcreteCommand()); invoker->setOnFinish(new ComplexConcreteCommand(ui, "cmd --version")); - Client::clientCode(invoker); + client::clientCode(invoker); delete ui; } -} // namespace Command +} // namespace command } // namespace #include "ExampleRegistry.h" @@ -132,7 +145,7 @@ class CommandExample : public IExample { std::string group() const override { return "dp/behavioral"; } std::string name() const override { return "Command"; } std::string description() const override { return "Command Pattern Example"; } - void execute() override { Command::run(); } + void execute() override { command::run(); } }; REGISTER_EXAMPLE(CommandExample, "dp/behavioral", "Command"); \ No newline at end of file diff --git a/src/dp/behavioral/Iterator.cpp b/src/dp/behavioral/Iterator.cpp index a1df34b..704cfc6 100644 --- a/src/dp/behavioral/Iterator.cpp +++ b/src/dp/behavioral/Iterator.cpp @@ -12,23 +12,22 @@ // UML: docs/uml/patterns_behavioral_iterator.drawio.svg #include -#include #include #include #include namespace { -namespace Iterator { +namespace iterator { class DataModel { private: - int m_value; + int value_; public: - explicit DataModel(int value) : m_value{value} {} + explicit DataModel(int value) : value_{value} {} - void setValue(int v) { m_value = v; } + void setValue(int v) { value_ = v; } - int getValue() const { return m_value; } + int getValue() const { return value_; } }; /** @@ -66,40 +65,40 @@ class IAggregate { template class VectorConcreteIterator : public IIterator { private: - const std::vector& m_data; - size_t m_currentIndex{0}; + const std::vector& data_; + size_t currentIndex_{0}; public: - explicit VectorConcreteIterator(const std::vector& data) : m_data{data} {} + explicit VectorConcreteIterator(const std::vector& data) : data_{data} {} - bool hasNext() const override { return m_currentIndex < m_data.size(); } + bool hasNext() const override { return currentIndex_ < data_.size(); } const T* next() override { if (hasNext()) { - return (T*)&m_data[m_currentIndex++]; - } else { - return nullptr; + return &data_[currentIndex_++]; } + + return nullptr; } }; template class ListConcreteIterator : public IIterator { private: - const std::list& m_data; - typename std::list::const_iterator m_it; + const std::list& data_; + typename std::list::const_iterator it_; public: explicit ListConcreteIterator(const std::list& data) - : m_data(data), m_it(m_data.begin()) {} + : data_(data), it_(data_.begin()) {} - bool hasNext() const override { return m_it != m_data.end(); } + bool hasNext() const override { return it_ != data_.end(); } const T* next() override { if (!hasNext()) return nullptr; - const T* ptr = &(*m_it); - ++m_it; + const T* ptr = &(*it_); + ++it_; return ptr; } }; @@ -111,26 +110,26 @@ class ListConcreteIterator : public IIterator { template class ListConreteAggregate : public IAggregate { private: - std::list m_data; + std::list data_; public: - void add(const T& i) { m_data.push_back(i); } + void add(const T& i) { data_.push_back(i); } IIterator* createIterator() override { - return new ListConcreteIterator(m_data); + return new ListConcreteIterator(data_); } }; template class VectorConcreteAggregate : public IAggregate { private: - std::vector m_data; + std::vector data_; public: - void add(const T& i) { m_data.push_back(i); } + void add(const T& i) { data_.push_back(i); } IIterator* createIterator() override { - return new VectorConcreteIterator(m_data); + return new VectorConcreteIterator(data_); } }; @@ -139,7 +138,7 @@ class VectorConcreteAggregate : public IAggregate { * This way the client isn’t coupled to concrete classes, allowing you to use * various collections and iterators with the same client code. */ -namespace Client { +namespace client { void clientCode(IAggregate* collection) { IIterator* iterator = collection->createIterator(); @@ -167,33 +166,33 @@ void clientCode(IAggregate* collection) { void run() { std::cout << "\nVectorConcreteAggregate\n"; - VectorConcreteAggregate intCollection; + VectorConcreteAggregate int_collection; for (int i = 0; i < 10; ++i) { - intCollection.add(i); + int_collection.add(i); } - Client::clientCode(&intCollection); + client::clientCode(&int_collection); std::cout << "\n"; - VectorConcreteAggregate dataCollection; + VectorConcreteAggregate data_collection; for (int i = 0; i < 10; ++i) { - dataCollection.add(DataModel(i * 10)); + data_collection.add(DataModel(i * 10)); } - Client::clientCode(&dataCollection); + client::clientCode(&data_collection); std::cout << "\nListConreteAggregate\n"; - ListConreteAggregate intCollection2; + ListConreteAggregate int_collection2; for (int i = 0; i < 10; ++i) { - intCollection2.add(i); + int_collection2.add(i); } - Client::clientCode(&intCollection2); + client::clientCode(&int_collection2); std::cout << "\n"; - ListConreteAggregate dataCollection2; + ListConreteAggregate data_collection2; for (int i = 0; i < 10; ++i) { - dataCollection2.add(DataModel(i * 10)); + data_collection2.add(DataModel(i * 10)); } - Client::clientCode(&dataCollection2); + client::clientCode(&data_collection2); } -} // namespace Iterator +} // namespace iterator } // namespace #include "ExampleRegistry.h" @@ -205,7 +204,7 @@ class IteratorExample : public IExample { std::string description() const override { return "Iterator Pattern Example"; } - void execute() override { Iterator::run(); } + void execute() override { iterator::run(); } }; REGISTER_EXAMPLE(IteratorExample, "dp/behavioral", "Iterator"); \ No newline at end of file diff --git a/src/dp/behavioral/Mediator.cpp b/src/dp/behavioral/Mediator.cpp index e5d66dd..bc3cbfb 100644 --- a/src/dp/behavioral/Mediator.cpp +++ b/src/dp/behavioral/Mediator.cpp @@ -17,26 +17,27 @@ #include #include +#include #include namespace { -namespace Mediator { +namespace mediator { enum class Event { - CREATE = 0, - READ, - UPDATE, - DELETE, + kCreate = 0, + kRead, + kUpdate, + kDelete, }; -static inline const char* getEventName(const Event& e) { +inline const char* getEventName(const Event& e) { switch (e) { - case Event::CREATE: + case Event::kCreate: return "CREATE"; - case Event::READ: + case Event::kRead: return "READ"; - case Event::UPDATE: + case Event::kUpdate: return "UPDATE"; - case Event::DELETE: + case Event::kDelete: return "DELETE"; } return "invalid_event"; @@ -46,8 +47,8 @@ class IComponent { public: virtual ~IComponent() = default; - virtual void send(const Event e) = 0; - virtual void receive(const Event e) = 0; + virtual void send(const Event& e) = 0; + virtual void receive(const Event& e) = 0; }; /** @@ -60,7 +61,7 @@ class IComponent { class IMediator { public: virtual ~IMediator() = default; - virtual void registerComponent(IComponent* const c) = 0; + virtual void registerComponent(IComponent* const& c) = 0; virtual void notify(IComponent* sender, const Event& e) = 0; }; @@ -71,15 +72,15 @@ class IMediator { */ class ComponentMediator : public IMediator { private: - std::vector m_components; + std::vector components_; public: - void registerComponent(IComponent* const c) override { - m_components.push_back(c); + void registerComponent(IComponent* const& c) override { + components_.push_back(c); } void notify(IComponent* const sender, const Event& e) override { - for (auto c : m_components) { + for (auto* c : components_) { if (c != sender) { c->receive(e); } @@ -96,19 +97,18 @@ class ComponentMediator : public IMediator { */ class AbstractComponent : public IComponent { private: - const std::string m_id; + const std::string id_; protected: - IMediator* m_mediator; + IMediator* mediator_; void log(const Event& e, const std::string& msg) const { - std::cout << "\t" + msg + "-id:" + m_id + "-event:" + getEventName(e) + - "\n"; + std::cout << "\t" + msg + "-id:" + id_ + "-event:" + getEventName(e) + "\n"; } public: - explicit AbstractComponent(const std::string& id, + explicit AbstractComponent(std::string id, IMediator* const m = nullptr) - : m_id{id}, m_mediator{m} {}; + : id_{std::move(id)}, mediator_{m} {}; }; /** @@ -120,23 +120,23 @@ class ConreteComponent : public AbstractComponent { explicit ConreteComponent(const std::string& id, IMediator* const m = nullptr) : AbstractComponent{id, m} {} - void send(const Event e) override { + void send(const Event& e) override { log(e, "[SEND]"); - if (m_mediator != nullptr) - m_mediator->notify(this, e); + if (mediator_ != nullptr) + mediator_->notify(this, e); } - void receive(const Event e) override { + void receive(const Event& e) override { log(e, "[RECV]"); // Additional handling logic can go here } }; -namespace Client { +namespace client { void clientCode(IComponent* comp) { - comp->send(Event::READ); + comp->send(Event::kRead); } -} // namespace Client +} // namespace client void run() { IMediator* mediator = new ComponentMediator(); @@ -151,7 +151,7 @@ void run() { mediator->registerComponent(c4); // c2 triggers event => observed by others - Client::clientCode(c2); + client::clientCode(c2); delete mediator; delete c1; @@ -159,7 +159,7 @@ void run() { delete c3; delete c4; } -} // namespace Mediator +} // namespace mediator } // namespace #include "ExampleRegistry.h" @@ -171,7 +171,7 @@ class MediatorExample : public IExample { std::string description() const override { return "Mediator Pattern Example"; } - void execute() override { Mediator::run(); } + void execute() override { mediator::run(); } }; REGISTER_EXAMPLE(MediatorExample, "dp/behavioral", "Mediator"); \ No newline at end of file diff --git a/src/dp/behavioral/Memento.cpp b/src/dp/behavioral/Memento.cpp index 93d0f93..455da0e 100644 --- a/src/dp/behavioral/Memento.cpp +++ b/src/dp/behavioral/Memento.cpp @@ -12,9 +12,11 @@ #include #include #include +#include #include + namespace { -namespace Memento { +namespace memento { /** * Memento interface provides a way to retrieve the memento's metadata, such as * creation date or name. However, it doesn't expose the Originator's state. @@ -34,12 +36,12 @@ class IMemento { */ class ConcreteMemento : public IMemento { private: - std::string m_state; - std::string m_date; - std::string m_name; + std::string state_; + std::string date_; + std::string name_; public: - explicit ConcreteMemento(const std::string& state) : m_state{state} { + explicit ConcreteMemento(std::string state) : state_{std::move(state)} { // Get current time std::time_t now = std::time(nullptr); std::tm* t = std::localtime(&now); @@ -47,20 +49,20 @@ class ConcreteMemento : public IMemento { // Format date as YYYYMMDD_HHMMSS std::stringstream date_ss; date_ss << std::put_time(t, "%Y%m%d_%H%M%S"); - m_date = date_ss.str(); + date_ = date_ss.str(); // Append a random number for uniqueness int rand_num = std::rand() % 10000; // optional: limit size std::stringstream name_ss; - name_ss << "mem_" << m_date << "_" << rand_num; - m_name = name_ss.str(); + name_ss << "me" << date_ << "_" << rand_num; + name_ = name_ss.str(); } - std::string getName() const override { return m_name; }; + std::string getName() const override { return name_; }; - std::string getDate() const override { return this->m_date; }; + std::string getDate() const override { return this->date_; }; - std::string getState() const override { return this->m_state; } + std::string getState() const override { return this->state_; } }; /** @@ -70,42 +72,44 @@ class ConcreteMemento : public IMemento { */ class Originator { private: - std::string m_state; + std::string state_; + int dummy_{}; // Simulate new state using rand - static std::string generateRandomString(int len = 10) { + std::string generateRandomString(int len = 10) { // String literal concatenation - const char alphaNum[] = + const char alpha_num[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; - int strLen = sizeof(alphaNum) - 1; - std::string ranStr; + int str_len = sizeof(alpha_num) - 1; + std::string ran_str; for (int i = 0; i < len; ++i) { - ranStr += alphaNum[std::rand() % strLen]; + ran_str += alpha_num[std::rand() % str_len]; } - return ranStr; + dummy_++; + return ran_str; } public: - explicit Originator(const std::string& state) : m_state{state} { - std::cout << "[O]Initial state is: " << this->m_state << "\n"; + explicit Originator(std::string state) : state_{std::move(state)} { + std::cout << "[O]Initial state is: " << this->state_ << "\n"; } void operation() { std::cout << "[O]Doing something important.\n"; - this->m_state = this->generateRandomString(30); - std::cout << "[O]The state has changed to: " << this->m_state << "\n"; + this->state_ = this->generateRandomString(30); + std::cout << "[O]The state has changed to: " << this->state_ << "\n"; } // Save the current state inside a memento. - IMemento* save() { return new ConcreteMemento(this->m_state); } + IMemento* save() { return new ConcreteMemento(this->state_); } // Restores the Originator's state from a memento object. void restore(IMemento* mem) { - this->m_state = mem->getState(); - std::cout << "[O]The state has restored to: " << this->m_state << "\n"; + this->state_ = mem->getState(); + std::cout << "[O]The state has restored to: " << this->state_ << "\n"; delete mem; } @@ -118,77 +122,77 @@ class Originator { */ class CareTaker { private: - std::vector m_mementos; - Originator* m_originator; + std::vector mementos_; + Originator* originator_; public: - explicit CareTaker(Originator* const org) : m_originator{org} {} + explicit CareTaker(Originator* const org) : originator_{org} {} ~CareTaker() { - for (IMemento* m : m_mementos) { + for (IMemento* m : mementos_) { delete m; } } void backup() { std::cout << "[C]Saving Originator's state...\n"; - this->m_mementos.push_back(this->m_originator->save()); + this->mementos_.push_back(this->originator_->save()); } void undo() { - if (this->m_mementos.size() != 0) { - IMemento* mem = m_mementos.back(); - this->m_mementos.pop_back(); + if (this->mementos_.size() != 0) { + IMemento* mem = mementos_.back(); + this->mementos_.pop_back(); std::cout << "[C]Restoring state to: " << mem->getName() << "\n"; - this->m_originator->restore(mem); + this->originator_->restore(mem); } } void history() const { std::cout << "[C]The list of mementos:\n"; - for (const IMemento* m : m_mementos) { + for (const IMemento* m : mementos_) { std::cout << "\t" << m->getName() << "\n"; } } }; -namespace Client { +namespace client { void clientCode(Originator* const org) { - CareTaker* careTaker = new CareTaker(org); + auto* care_taker = new CareTaker(org); // 1 - careTaker->backup(); + care_taker->backup(); org->operation(); // 2 - careTaker->backup(); + care_taker->backup(); org->operation(); // 3 - careTaker->backup(); + care_taker->backup(); org->operation(); - careTaker->history(); - careTaker->undo(); - careTaker->undo(); - careTaker->history(); - careTaker->undo(); + care_taker->history(); + care_taker->undo(); + care_taker->undo(); + care_taker->history(); + care_taker->undo(); - // [P] The previous state can’t be restored directly because m_state is + // [P] The previous state can’t be restored directly because state is // private. We need a Memento to save and recover internal state safely. } -} // namespace Client +} // namespace client void run() { // Gen seed - std::srand(static_cast(std::time(NULL))); + std::srand(static_cast(std::time(nullptr))); - Originator* origin = new Originator("Hello World"); - Client::clientCode(origin); + auto* origin = new Originator("Hello World"); + client::clientCode(origin); delete origin; } -} // namespace Memento +} // namespace memento } // namespace #include "ExampleRegistry.h" @@ -200,7 +204,7 @@ class MementoExample : public IExample { std::string description() const override { return "Memento Pattern Example "; } - void execute() override { Memento::run(); } + void execute() override { memento::run(); } }; REGISTER_EXAMPLE(MementoExample, "dp/behavioral", "Memento"); \ No newline at end of file diff --git a/src/dp/behavioral/Observer.cpp b/src/dp/behavioral/Observer.cpp index e90c762..0cde6f4 100644 --- a/src/dp/behavioral/Observer.cpp +++ b/src/dp/behavioral/Observer.cpp @@ -17,24 +17,26 @@ #include namespace { -namespace Observer { +namespace observer { enum class Event { - CREATE = 0, - READ, - UPDATE, - DELETE, + kCreate = 0, + kRead, + kUpdate, + kDelete, }; -static inline const char* getEventName(const Event& e) { +inline const char* getEventName( + const Event& + e) { // 'getEventName' is a static definition in anonymous namespace switch (e) { - case Event::CREATE: + case Event::kCreate: return "CREATE"; - case Event::READ: + case Event::kRead: return "READ"; - case Event::UPDATE: + case Event::kUpdate: return "UPDATE"; - case Event::DELETE: + case Event::kDelete: return "DELETE"; } return "invalid_event"; @@ -52,7 +54,7 @@ class IListenerObserver { virtual ~IListenerObserver() = default; // update - virtual void update(const Event e) = 0; + virtual void update(const Event& e) = 0; }; /** @@ -66,7 +68,7 @@ class IListenerObserver { */ class IWidgetSubject { public: - virtual ~IWidgetSubject(){}; + virtual ~IWidgetSubject() = default; // addListener virtual void attach(IListenerObserver* observer) = 0; // removeLister @@ -77,20 +79,20 @@ class IWidgetSubject { class ButtonConcreteSubject : public IWidgetSubject { private: - std::list m_listeners; + std::list listeners_; public: void attach(IListenerObserver* observer) override { - m_listeners.push_back(observer); + listeners_.push_back(observer); } void detach(IListenerObserver* observer) override { - m_listeners.remove(observer); + listeners_.remove(observer); } void notify(const Event& e) override { std::cout << "[Subject] notify event-" << getEventName(e) << "\n"; - for (IListenerObserver* o : m_listeners) { + for (IListenerObserver* o : listeners_) { o->update(e); } } @@ -98,16 +100,16 @@ class ButtonConcreteSubject : public IWidgetSubject { class AbstractListenerObserver : public IListenerObserver { private: - int m_num; - inline static int num_observers = 0; + int nu_; + inline static int nuobservers_ = 0; protected: void log(const Event& e) const { - std::cout << "\t-id:" << m_num << "-event:" << getEventName(e) << "\n"; + std::cout << "\t-id:" << nu_ << "-event:" << getEventName(e) << "\n"; } public: - explicit AbstractListenerObserver() { m_num = ++num_observers; } + explicit AbstractListenerObserver() { nu_ = ++nuobservers_; } }; /** @@ -117,22 +119,22 @@ class AbstractListenerObserver : public IListenerObserver { */ class ConcreteListenerObserverA : public AbstractListenerObserver { private: - static const inline char* type = "A-type"; + static const inline char* type_ = "A-type"; public: - void update(const Event e) override { - std::cout << "\tListener: " << type; + void update(const Event& e) override { + std::cout << "\tListener: " << type_; log(e); } }; class ConcreteListenerObserverB : public AbstractListenerObserver { private: - static const inline char* type = "B-type"; + static const inline char* type_ = "B-type"; public: - void update(const Event e) override { - std::cout << "\tListener: " << type; + void update(const Event& e) override { + std::cout << "\tListener: " << type_; log(e); } }; @@ -141,11 +143,11 @@ class ConcreteListenerObserverB : public AbstractListenerObserver { * The Client creates publisher and subscriber objects separately * and then registers subscribers for publisher updates. */ -namespace Client { +namespace client { void clientCode(IWidgetSubject* const s) { - s->notify(Event::UPDATE); + s->notify(Event::kUpdate); } -} // namespace Client +} // namespace client void run() { IWidgetSubject* btn = new ButtonConcreteSubject(); @@ -159,11 +161,11 @@ void run() { btn->attach(listener_2); btn->attach(listener_3); btn->attach(listener_4); - Client::clientCode(btn); + client::clientCode(btn); std::cout << "Remove listener2\n"; btn->detach(listener_2); - Client::clientCode(btn); + client::clientCode(btn); delete btn; delete listener_1; @@ -172,7 +174,7 @@ void run() { delete listener_4; } -} // namespace Observer +} // namespace observer } // namespace #include "ExampleRegistry.h" @@ -184,7 +186,7 @@ class ObserverExample : public IExample { std::string description() const override { return "Observer Pattern Example"; } - void execute() override { Observer::run(); } + void execute() override { observer::run(); } }; REGISTER_EXAMPLE(ObserverExample, "dp/behavioral", "Observer"); \ No newline at end of file diff --git a/src/dp/behavioral/State.cpp b/src/dp/behavioral/State.cpp index 6c4517d..fcdd93e 100644 --- a/src/dp/behavioral/State.cpp +++ b/src/dp/behavioral/State.cpp @@ -15,7 +15,7 @@ #include #include namespace { -namespace State { +namespace state { class DeviceContext; /** @@ -36,10 +36,10 @@ class IState { */ class AbstractState : public IState { protected: - DeviceContext* m_ctx; + DeviceContext* ctx_; public: - void setContext(DeviceContext* ctx) override { this->m_ctx = ctx; } + void setContext(DeviceContext* ctx) override { this->ctx_ = ctx; } }; /** @@ -50,25 +50,23 @@ class AbstractState : public IState { */ class DeviceContext { private: - IState* m_state; + IState* state_{}; public: - explicit DeviceContext(IState* state) : m_state{nullptr} { - this->changeState(state); - } + explicit DeviceContext(IState* state) { this->changeState(state); } - ~DeviceContext() { delete m_state; } + ~DeviceContext() { delete state_; } void changeState(IState* state) { std::cout << "[DeviceContext]: Changing state\n"; - if (this->m_state != nullptr) { - delete this->m_state; - } - this->m_state = state; - this->m_state->setContext(this); + + delete this->state_; // delete nullptr has no effect + + this->state_ = state; + this->state_->setContext(this); } - void operation() { this->m_state->handle(); } + void operation() { this->state_->handle(); } }; /** @@ -91,13 +89,13 @@ class ErrorConcreteState : public AbstractState { std::cout << "[Error] Device error! Reset required.\n"; // After recover => go Idle - this->m_ctx->changeState(new IdeConcreteState()); + this->ctx_->changeState(new IdeConcreteState()); } }; void IdeConcreteState::handle() { std::cout << "[Ide] Device is idle. Waiting...\n"; - this->m_ctx->changeState(new ProcessingConcreteState()); + this->ctx_->changeState(new ProcessingConcreteState()); } void ProcessingConcreteState::handle() { @@ -105,31 +103,27 @@ void ProcessingConcreteState::handle() { bool ok = true; // Example processing result static int index = 0; index++; - if (index % 2 == 0) { - ok = true; - } else { - ok = false; - } + ok = index % 2 == 0; if (ok) { // Back to idle after finishing job - this->m_ctx->changeState(new IdeConcreteState()); + this->ctx_->changeState(new IdeConcreteState()); } else { - this->m_ctx->changeState(new ErrorConcreteState()); + this->ctx_->changeState(new ErrorConcreteState()); } } -namespace Client { +namespace client { void clientCode(DeviceContext* const device) { device->operation(); } -} // namespace Client +} // namespace client void run() { - DeviceContext* device = new DeviceContext(new IdeConcreteState()); - for (int loopIdx = 0; loopIdx < 10; ++loopIdx) - Client::clientCode(device); + auto* device = new DeviceContext(new IdeConcreteState()); + for (int loop_idx = 0; loop_idx < 10; ++loop_idx) + client::clientCode(device); delete device; } -} // namespace State +} // namespace state } // namespace #include "ExampleRegistry.h" @@ -139,7 +133,7 @@ class StateExample : public IExample { std::string group() const override { return "dp/behavioral"; } std::string name() const override { return "State"; } std::string description() const override { return "State Pattern Example"; } - void execute() override { State::run(); } + void execute() override { state::run(); } }; REGISTER_EXAMPLE(StateExample, "dp/behavioral", "State"); \ No newline at end of file diff --git a/src/dp/behavioral/Strategy.cpp b/src/dp/behavioral/Strategy.cpp index 8b41a4c..50e0b0a 100644 --- a/src/dp/behavioral/Strategy.cpp +++ b/src/dp/behavioral/Strategy.cpp @@ -13,8 +13,9 @@ #include #include +#include namespace { -namespace Strategy { +namespace strategy { class IExportStrategy { public: virtual ~IExportStrategy() = default; @@ -23,19 +24,19 @@ class IExportStrategy { class ExportContext { private: - std::string m_content; - IExportStrategy* m_strategy; + std::string content_; + IExportStrategy* strategy_; public: - ~ExportContext() { delete m_strategy; } + ~ExportContext() { delete strategy_; } explicit ExportContext(std::string content, IExportStrategy* const strategy = nullptr) - : m_content{content}, m_strategy{strategy} {} + : content_{std::move(content)}, strategy_{strategy} {} void setExportStrategy(IExportStrategy* const strategy) { - delete m_strategy; - this->m_strategy = strategy; + delete strategy_; + this->strategy_ = strategy; } // The old approach using if-else for each format is commented out: @@ -55,19 +56,18 @@ class ExportContext { // only holds data. // ====================================================================================== std::string exportDocument() const { - if (m_strategy != nullptr) { - return this->m_strategy->executeExportData(this->m_content); - } else { - std::cout << "Context: Strategy isn't set\n"; - return ""; + if (strategy_ != nullptr) { + return this->strategy_->executeExportData(this->content_); } + std::cout << "Context: Strategy isn't set\n"; + return ""; } }; class JsonExportStrategy : public IExportStrategy { public: std::string executeExportData(const std::string& content) const override { - return "{\"content\": \"" + content + "\" }"; + return R"({"content": ")" + content + "\" }"; } }; @@ -78,27 +78,27 @@ class HtmlExportStrategy : public IExportStrategy { } }; -namespace Client { +namespace client { void clientCode(const ExportContext* ctx) { std::cout << ctx->exportDocument(); std::cout << "\n"; } -} // namespace Client +} // namespace client void run() { - ExportContext* ctx = new ExportContext{"This is the report content."}; - Client::clientCode(ctx); + auto* ctx = new ExportContext{"This is the report content."}; + client::clientCode(ctx); std::cout << " ===HTML Export ===\n"; ctx->setExportStrategy(new HtmlExportStrategy()); - Client::clientCode(ctx); + client::clientCode(ctx); std::cout << " ===JSON Export ===\n"; ctx->setExportStrategy(new JsonExportStrategy()); - Client::clientCode(ctx); + client::clientCode(ctx); delete ctx; } -} // namespace Strategy +} // namespace strategy } // namespace #include "ExampleRegistry.h" @@ -110,7 +110,7 @@ class StrategyExample : public IExample { std::string description() const override { return "Strategy Pattern Example"; } - void execute() override { Strategy::run(); } + void execute() override { strategy::run(); } }; REGISTER_EXAMPLE(StrategyExample, "dp/behavioral", "Strategy"); \ No newline at end of file diff --git a/src/dp/behavioral/TemplateMethod.cpp b/src/dp/behavioral/TemplateMethod.cpp index f30f939..84ef180 100644 --- a/src/dp/behavioral/TemplateMethod.cpp +++ b/src/dp/behavioral/TemplateMethod.cpp @@ -17,14 +17,14 @@ #include namespace { -namespace TemplateMethod { +namespace template_method { class AbstractClass { public: virtual ~AbstractClass() = default; // Template Method (non-virtual => cannot be overridden) // Defines the algorithm's skeleton and ensures subclasses cannot change the // flow. - void templateMethod() const { + void templateMethod() { baseOperation1(); abstractMethod1(); hookOperation1(); @@ -37,14 +37,16 @@ class AbstractClass { protected: // 1. Base operations: These have full implementations and cannot be // overridden. - void baseOperation1() const { + void baseOperation1() { // Common logic step 1 std::cout << "[AbstractClass]\t Executed base operation - 1\n"; + dummy_++; } - void baseOperation2() const { + void baseOperation2() { // Common logic step 2 std::cout << "[AbstractClass]\t Executed base operation - 2\n"; + dummy_++; } // 2. Hook methods: Subclasses may override them to extend behavior, but @@ -55,6 +57,9 @@ class AbstractClass { // 3. Abstract methods: Subclasses MUST provide implementations. virtual void abstractMethod1() const = 0; virtual void abstractMethod2() const = 0; + + private: + int dummy_{}; }; class ConcreteClass1 : public AbstractClass { @@ -83,24 +88,24 @@ class ConcreteClass2 : public AbstractClass { } }; -namespace Client { -void clientCode(const AbstractClass* clazz) { +namespace client { +void clientCode(AbstractClass* clazz) { clazz->templateMethod(); } -} // namespace Client +} // namespace client void run() { std::cout << "\t[ConcreteClass1] Executed templateMethod\n"; AbstractClass* clazz1 = new ConcreteClass1(); - Client::clientCode(clazz1); + client::clientCode(clazz1); std::cout << "\t[ConcreteClass1] Executed templateMethod\n"; AbstractClass* clazz2 = new ConcreteClass2(); - Client::clientCode(clazz2); + client::clientCode(clazz2); delete clazz1; delete clazz2; } -} // namespace TemplateMethod +} // namespace template_method } // namespace #include "ExampleRegistry.h" @@ -112,7 +117,7 @@ class TemplateMethodExample : public IExample { std::string description() const override { return "TemplateMethod Pattern Example"; } - void execute() override { TemplateMethod::run(); } + void execute() override { template_method::run(); } }; REGISTER_EXAMPLE(TemplateMethodExample, "dp/behavioral", "TemplateMethod"); \ No newline at end of file diff --git a/src/dp/behavioral/Visitor.cpp b/src/dp/behavioral/Visitor.cpp index 87be60a..4da0d88 100644 --- a/src/dp/behavioral/Visitor.cpp +++ b/src/dp/behavioral/Visitor.cpp @@ -8,10 +8,11 @@ #include #include +#include #include namespace { -namespace Visitor { +namespace visitor { class TextConcreteElement; class ImageConcreteElement; class TableConcreteElement; @@ -54,19 +55,19 @@ class IElement { */ class DocumentConcreteStructure { private: - std::vector m_elements; + std::vector elements_; public: ~DocumentConcreteStructure() { - for (IElement* e : this->m_elements) { + for (IElement* e : this->elements_) { delete e; } - m_elements.clear(); + elements_.clear(); } - void add(IElement* e) { m_elements.push_back(e); } + void add(IElement* e) { elements_.push_back(e); } - std::vector& get() { return this->m_elements; }; + std::vector& get() { return this->elements_; }; }; /** @@ -79,35 +80,35 @@ class DocumentConcreteStructure { */ class TextConcreteElement : public IElement { private: - std::string m_content; + std::string content_; public: - explicit TextConcreteElement(const std::string& c) : m_content{c} {}; - std::string getContent() const { return this->m_content; } + explicit TextConcreteElement(std::string c) : content_{std::move(c)} {}; + std::string getContent() const { return this->content_; } void accept(IVisitor* visitor) override { visitor->visitText(this); } }; class ImageConcreteElement : public IElement { private: - std::string m_path; + std::string path_; public: - explicit ImageConcreteElement(const std::string& p) : m_path{p} {}; + explicit ImageConcreteElement(std::string p) : path_{std::move(p)} {}; - std::string getPath() const { return this->m_path; } + std::string getPath() const { return this->path_; } void accept(IVisitor* visitor) override { visitor->visitImage(this); } }; class TableConcreteElement : public IElement { private: - int m_rows, m_cols; + int rows_, cols_; public: - TableConcreteElement(int r, int c) : m_rows{r}, m_cols{c} {}; - int getRows() const { return this->m_rows; } - int getCols() const { return this->m_cols; } + TableConcreteElement(int r, int c) : rows_{r}, cols_{c} {}; + int getRows() const { return this->rows_; } + int getCols() const { return this->cols_; } void accept(IVisitor* visitor) override { visitor->visitTable(this); } }; @@ -140,16 +141,15 @@ class HtmlExportConcreteVisitor : public IVisitor { class JsonExportConcreteVisitor : public IVisitor { void visitText(const TextConcreteElement* t) override { - std::cout << "{ \"type\": \"text\", \"content\": \"" << t->getContent() + std::cout << R"({ "type": "text", "content": ")" << t->getContent() << "\" }\n"; } void visitImage(const ImageConcreteElement* i) override { - std::cout << "{ \"type\": \"image\", \"path\": \"" << i->getPath() - << "\" }\n"; + std::cout << R"({ "type": "image", "path": ")" << i->getPath() << "\" }\n"; } void visitTable(const TableConcreteElement* t) override { - std::cout << "{ \"type\": \"table\", \"rows\": " << t->getRows() + std::cout << R"({ "type": "table", "rows": )" << t->getRows() << ", \"cols\": " << t->getCols() << " }\n"; } }; @@ -178,7 +178,7 @@ class MarkdownExportConcreteVisitor : public IVisitor { * clients aren’t aware of all the concrete element classes because they work * with objects from that collection via some abstract interface. */ -namespace Client { +namespace client { void clientCode(DocumentConcreteStructure* const doc, IVisitor* const visitor) { // [P2] Instead of adding exportHtml(), exportMarkdown(), exportJson() in each // element, we use the Visitor pattern to separate data from behavior. This @@ -188,9 +188,9 @@ void clientCode(DocumentConcreteStructure* const doc, IVisitor* const visitor) { ele->accept(visitor); } } -} // namespace Client +} // namespace client void run() { - DocumentConcreteStructure* document = new DocumentConcreteStructure(); + auto* document = new DocumentConcreteStructure(); // Add images document->add(new ImageConcreteElement("header.png")); document->add(new ImageConcreteElement("diagram1.png")); @@ -218,22 +218,22 @@ void run() { IVisitor* visitor = new HtmlExportConcreteVisitor(); std::cout << " ===HTML Export ===\n"; - Client::clientCode(document, visitor); + client::clientCode(document, visitor); std::cout << " ==================\n"; visitor = new JsonExportConcreteVisitor(); std::cout << " ===JSON Export ===\n"; - Client::clientCode(document, visitor); + client::clientCode(document, visitor); std::cout << " ==================\n"; visitor = new MarkdownExportConcreteVisitor(); std::cout << " ===MD Export ===\n"; - Client::clientCode(document, visitor); + client::clientCode(document, visitor); std::cout << " ==================\n"; delete visitor; delete document; } -} // namespace Visitor +} // namespace visitor } // namespace #include "ExampleRegistry.h" @@ -243,7 +243,7 @@ class VisitorExample : public IExample { std::string group() const override { return "dp/behavioral"; } std::string name() const override { return "Visitor"; } std::string description() const override { return "Visitor Pattern Example"; } - void execute() override { Visitor::run(); } + void execute() override { visitor::run(); } }; REGISTER_EXAMPLE(VisitorExample, "dp/behavioral", "Visitor"); \ No newline at end of file diff --git a/src/dp/creational/AbstractFactory.cpp b/src/dp/creational/AbstractFactory.cpp index 6f57506..7853531 100644 --- a/src/dp/creational/AbstractFactory.cpp +++ b/src/dp/creational/AbstractFactory.cpp @@ -15,7 +15,7 @@ #include #include namespace { -namespace AbstractFactory { +namespace abstract_factory { /** * The Product interface declares the operations that all concrete products must * implement. @@ -128,7 +128,7 @@ class MacOsProductFactory : public IProductAbstractFactory { * types: AbstractFactory and AbstractProduct. This lets you pass any factory or * product subclass to the client code without breaking it. */ -namespace ClientCode { +namespace client_code { void clientCode(IProductAbstractFactory* f) { ICMakeProduct* cmake = f->createCMakeProduct(); IGdbProduct* gdb = f->createGdbProduct(); @@ -138,29 +138,30 @@ void clientCode(IProductAbstractFactory* f) { delete cmake; delete gdb; } -} // namespace ClientCode +} // namespace client_code // static redudant inside anonymous namespace IProductAbstractFactory* createProductFactory(const std::string& os) { if (os == "linux") { return new LinuxProductFactory(); - } else if (os == "windows") { + } + if (os == "windows") { return new WindowsProductFactory(); - } else if (os == "macos") { + } + if (os == "macos") { return new MacOsProductFactory(); - } else { - std::cout << "OS not support yet - " << os << "\n"; - return nullptr; } + std::cout << "OS not support yet - " << os << "\n"; + return nullptr; } void run() { std::string os = "linux"; IProductAbstractFactory* factory = createProductFactory(os); - ClientCode::clientCode(factory); + client_code::clientCode(factory); delete factory; } -} // namespace AbstractFactory +} // namespace abstract_factory } // namespace #include "ExampleRegistry.h" @@ -172,7 +173,7 @@ class AbstractFactoryExample : public IExample { std::string description() const override { return "AbstractFactory Pattern Example"; } - void execute() override { AbstractFactory::run(); } + void execute() override { abstract_factory::run(); } }; REGISTER_EXAMPLE(AbstractFactoryExample, "dp/creational", "AbstractFactory"); \ No newline at end of file diff --git a/src/dp/creational/Builder.cpp b/src/dp/creational/Builder.cpp index 13024f0..fbccb2d 100644 --- a/src/dp/creational/Builder.cpp +++ b/src/dp/creational/Builder.cpp @@ -10,24 +10,23 @@ // UML: docs/uml/patterns_behavioral_iterator.drawio.svg #include -#include #include #include namespace { -namespace BuilderPattern { +namespace builder_pattern { class Product { private: - std::vector m_parts; + std::vector parts_; public: - void addPart(const std::string& part) { m_parts.push_back(part); } + void addPart(const std::string& part) { parts_.push_back(part); } void print() const { std::cout << "Product parts: "; - for (size_t i = 0; i < m_parts.size(); ++i) { - std::cout << m_parts[i]; - if (i + 1 < m_parts.size()) + for (size_t i = 0; i < parts_.size(); ++i) { + std::cout << parts_[i]; + if (i + 1 < parts_.size()) std::cout << ", "; } std::cout << "\n\n"; @@ -46,43 +45,43 @@ class IBuilder { virtual IBuilder& producePart2() = 0; virtual IBuilder& producePart3() = 0; - virtual Product* const build() = 0; + virtual Product* build() = 0; }; class AbstractBuilder : public IBuilder { protected: - Product* m_product; + Product* product_; public: - explicit AbstractBuilder() { m_product = new Product(); } + explicit AbstractBuilder() { product_ = new Product(); } - ~AbstractBuilder() { delete m_product; } + ~AbstractBuilder() override { delete product_; } AbstractBuilder(const AbstractBuilder& other) { - if (m_product != nullptr) { - delete m_product; - } - m_product = new Product(); - *m_product = *other.m_product; + + delete product_; + + product_ = new Product(); + *product_ = *other.product_; } AbstractBuilder& operator=(const AbstractBuilder& other) { if (this == &other) { return *this; } - if (m_product != nullptr) { - delete m_product; - } - m_product = new Product(); - *m_product = *other.m_product; + + delete product_; + product_ = new Product(); + *product_ = *other.product_; + return *this; } - IBuilder& reset() override final { - if (m_product != nullptr) { - delete m_product; - } - m_product = new Product(); + // the child classes are no longer override this function + IBuilder& reset() final { + + delete product_; + product_ = new Product(); return *this; } @@ -96,44 +95,44 @@ class AbstractBuilder : public IBuilder { class SimpleBuilder : public AbstractBuilder { public: IBuilder& producePart1() override { - m_product->addPart("PART1"); + product_->addPart("PART1"); return *this; } IBuilder& producePart2() override { - m_product->addPart("PART2"); + product_->addPart("PART2"); return *this; } IBuilder& producePart3() override { - m_product->addPart("PART3"); + product_->addPart("PART3"); return *this; } - Product* const build() override { return m_product; } + Product* build() override { return product_; } }; class ComplexBuilder : public AbstractBuilder { public: IBuilder& producePart1() override { - m_product->addPart("PART_1-X9a7Fq!2@Lm#48Z"); + product_->addPart("PART_1-X9a7Fq!2@Lm#48Z"); return *this; } IBuilder& producePart2() override { - m_product->addPart("PART_2-X9a7Fq!2@Lm#48Z"); + product_->addPart("PART_2-X9a7Fq!2@Lm#48Z"); return *this; } IBuilder& producePart3() override { - m_product->addPart("PART_3-X9a7Fq!2@Lm#48Z"); + product_->addPart("PART_3-X9a7Fq!2@Lm#48Z"); return *this; } - Product* const build() override { return m_product; } + Product* build() override { return product_; } }; -namespace Client { +namespace client { void clientCode(IBuilder* const builder) { const Product* product1 = (*builder).producePart1().producePart2().producePart3().build(); @@ -148,17 +147,17 @@ void run() { { std::cout << "ConcreteBuilder: Simple\n"; IBuilder* builder = new SimpleBuilder(); - Client::clientCode(builder); + client::clientCode(builder); delete builder; } { std::cout << "ConcreteBuilder: Complex\n"; IBuilder* builder = new ComplexBuilder(); - Client::clientCode(builder); + client::clientCode(builder); delete builder; } } -} // namespace BuilderPattern +} // namespace builder_pattern } // namespace #include "ExampleRegistry.h" @@ -168,7 +167,7 @@ class BuilderExample : public IExample { std::string group() const override { return "dp/creational"; } std::string name() const override { return "Builder"; } std::string description() const override { return "Builder Pattern Example"; } - void execute() override { BuilderPattern::run(); } + void execute() override { builder_pattern::run(); } }; REGISTER_EXAMPLE(BuilderExample, "dp/creational", "Builder"); \ No newline at end of file diff --git a/src/dp/creational/FactoryMethod.cpp b/src/dp/creational/FactoryMethod.cpp index 7160e62..89e42b2 100644 --- a/src/dp/creational/FactoryMethod.cpp +++ b/src/dp/creational/FactoryMethod.cpp @@ -15,7 +15,7 @@ #include #include namespace { -namespace FactoryMethod { +namespace factory_method { /** * The Product interface declares the operations that all concrete products must * implement. @@ -68,7 +68,7 @@ class IGdbFactory { class AbstractGdbFactory : public IGdbFactory { public: // Call the factory method to create a Product object. - void launchGdb() override final { + void launchGdb() final { IGdbProduct* gdb = this->factoryMethod(); gdb->launch(); delete gdb; @@ -101,33 +101,34 @@ class MacOsGdbFactory : public AbstractGdbFactory { * its base interface. As long as the client keeps working with the creator via * the base interface, you can pass it any creator's subclass. */ -namespace ClientCode { +namespace client_code { void clientCode(IGdbFactory* gdb) { if (gdb != nullptr) gdb->launchGdb(); } -} // namespace ClientCode +} // namespace client_code IGdbFactory* createGdbFactory(const std::string& os) { if (os == "linux") { return new LinuxGdbFactory(); - } else if (os == "windows") { + } + if (os == "windows") { return new WindowsGdbFactory(); - } else if (os == "macos") { + } + if (os == "macos") { return new MacOsGdbFactory(); - } else { - std::cout << "OS not support yet - " << os << "\n"; - return nullptr; } + std::cout << "OS not support yet - " << os << "\n"; + return nullptr; } void run() { std::string os = "linux"; IGdbFactory* gdb = createGdbFactory(os); - ClientCode::clientCode(gdb); + client_code::clientCode(gdb); delete gdb; } -} // namespace FactoryMethod +} // namespace factory_method } // namespace #include "ExampleRegistry.h" @@ -139,7 +140,7 @@ class FactoryMethodExample : public IExample { std::string description() const override { return "FactoryMethod Pattern Example"; } - void execute() override { FactoryMethod::run(); } + void execute() override { factory_method::run(); } }; REGISTER_EXAMPLE(FactoryMethodExample, "dp/creational", "FactoryMethod"); \ No newline at end of file diff --git a/src/dp/creational/Prototype.cpp b/src/dp/creational/Prototype.cpp index daa40bd..50010ea 100644 --- a/src/dp/creational/Prototype.cpp +++ b/src/dp/creational/Prototype.cpp @@ -9,8 +9,9 @@ #include #include +#include namespace { -namespace Prototy { +namespace prototy { /* * Prototype interface declares the cloning methods. @@ -31,32 +32,32 @@ class IExtensionPrototype { */ class LoggerExtension : public IExtensionPrototype { private: - std::string m_logLevel; + std::string logLevel_; public: - explicit LoggerExtension(const std::string& level = "DEBUG") - : m_logLevel{level} {} + explicit LoggerExtension(std::string level = "DEBUG") + : logLevel_{std::move(level)} {} IExtensionPrototype* clone() override { return new LoggerExtension(*this); } void execute() const override { - std::cout << "[Logger] log level: " << m_logLevel << "\n"; + std::cout << "[Logger] log level: " << logLevel_ << "\n"; } }; class AnalyticsExtension : public IExtensionPrototype { private: - int m_sRate; + int sRate_; public: - explicit AnalyticsExtension(int level = 1) : m_sRate{level} {} + explicit AnalyticsExtension(int level = 1) : sRate_{level} {} IExtensionPrototype* clone() override { return new AnalyticsExtension(*this); } void execute() const override { - std::cout << "[Analytics] sampling rate: " << m_sRate << "\n"; + std::cout << "[Analytics] sampling rate: " << sRate_ << "\n"; } }; @@ -68,22 +69,22 @@ class AnalyticsExtension : public IExtensionPrototype { */ class ExtensionPrototypeRegistry { private: - std::unordered_map prototypes; + std::unordered_map prototypes_; public: ~ExtensionPrototypeRegistry() { - for (auto it = prototypes.begin(); it != prototypes.end();) { - delete it->second; // free the pointer - it = prototypes.erase(it); // erase and move to next + for (auto it = prototypes_.begin(); it != prototypes_.end();) { + delete it->second; // free the pointer + it = prototypes_.erase(it); // erase and move to next } } void registerExtension(const std::string& id, IExtensionPrototype* proto) { - prototypes[id] = proto; + prototypes_[id] = proto; } IExtensionPrototype* create(const std::string& id) const { - auto it = prototypes.find(id); - if (it != prototypes.end()) { + auto it = prototypes_.find(id); + if (it != prototypes_.end()) { return it->second->clone(); } return nullptr; @@ -93,28 +94,28 @@ class ExtensionPrototypeRegistry { /* * Client creates a new object by asking a prototype to clone itself */ -namespace Client { +namespace client { void clientCode(const ExtensionPrototypeRegistry* const registry) { - IExtensionPrototype* loggerEtx = registry->create("logger"); - loggerEtx->execute(); - IExtensionPrototype* analyxEtx = registry->create("analyze"); - analyxEtx->execute(); + IExtensionPrototype* logger_etx = registry->create("logger"); + logger_etx->execute(); + IExtensionPrototype* analyx_etx = registry->create("analyze"); + analyx_etx->execute(); - delete loggerEtx; - delete analyxEtx; + delete logger_etx; + delete analyx_etx; } -} // namespace Client +} // namespace client void run() { - ExtensionPrototypeRegistry* registry = new ExtensionPrototypeRegistry(); + auto* registry = new ExtensionPrototypeRegistry(); registry->registerExtension("logger", new LoggerExtension("DEBUG")); registry->registerExtension("analyze", new AnalyticsExtension(1200)); - Client::clientCode(registry); + client::clientCode(registry); delete registry; } -} // namespace Prototy +} // namespace prototy } // namespace #include "ExampleRegistry.h" @@ -126,7 +127,7 @@ class PrototypeExample : public IExample { std::string description() const override { return "Prototype Pattern Example"; } - void execute() override { Prototy::run(); } + void execute() override { prototy::run(); } }; REGISTER_EXAMPLE(PrototypeExample, "dp/creational", "Prototype"); \ No newline at end of file diff --git a/src/dp/creational/Singleton.cpp b/src/dp/creational/Singleton.cpp index 805c3db..0ce22a4 100644 --- a/src/dp/creational/Singleton.cpp +++ b/src/dp/creational/Singleton.cpp @@ -13,7 +13,7 @@ #include namespace { -namespace SingletonPattern { +namespace singleton_pattern { /** * The Singleton class defines the `GetInstance` method that serves as an @@ -22,8 +22,9 @@ namespace SingletonPattern { */ class Singleton { private: - static inline Singleton* instance = nullptr; - static inline int num = 0; + static inline Singleton* instance_ = nullptr; + static inline int num_ = 0; + int dummy_{}; /** * The Singleton's constructor should always be private to prevent direct * construction calls with the `new` operator. @@ -38,36 +39,37 @@ class Singleton { Singleton& operator=(const Singleton& other) = delete; static Singleton* getInstance() { - if (instance == nullptr) { - instance = new Singleton(); - num++; + if (instance_ == nullptr) { + instance_ = new Singleton(); + num_++; } - return instance; + return instance_; } - void operation() const { - std::cout << "Singleton operating num:" << num << "\n"; + void operation() { + std::cout << "Singleton operating num:" << num_ << "\n"; + dummy_++; } }; -namespace Client { -void clientCode(const Singleton* const s) { +namespace client { +void clientCode(Singleton* const s) { s->operation(); } -} // namespace Client +} // namespace client void run() { - const Singleton* s1 = Singleton::getInstance(); - Client::clientCode(s1); + Singleton* s1 = Singleton::getInstance(); + client::clientCode(s1); - const Singleton* s2 = Singleton::getInstance(); - Client::clientCode(s2); + Singleton* s2 = Singleton::getInstance(); + client::clientCode(s2); // Singleton* s3 = new Singleton(); // ERROR } -} // namespace SingletonPattern +} // namespace singleton_pattern } // namespace #include "ExampleRegistry.h" @@ -79,7 +81,7 @@ class SingletonExample : public IExample { std::string description() const override { return "Singleton Pattern Example"; } - void execute() override { SingletonPattern::run(); } + void execute() override { singleton_pattern::run(); } }; REGISTER_EXAMPLE(SingletonExample, "dp/creational", "Singleton"); \ No newline at end of file diff --git a/src/dp/structural/Adapter.cpp b/src/dp/structural/Adapter.cpp index e812403..82abb36 100644 --- a/src/dp/structural/Adapter.cpp +++ b/src/dp/structural/Adapter.cpp @@ -9,7 +9,7 @@ #include -namespace AdapterPattern { +namespace adapter_pattern { /** * The Adaptee contains some useful behavior, but its interface is incompatible * with the existing client code. The Adaptee needs some adaptation before the @@ -17,9 +17,13 @@ namespace AdapterPattern { */ class Adaptee { public: - static std::string specificRequest() { + std::string specificRequest() { + dummy_++; return "Adaptee: The adaptee's behavior."; } + + private: + int dummy_{}; }; /** @@ -27,9 +31,7 @@ class Adaptee { */ class Target { public: - virtual std::string request() const { - return " Target: The target's behavior."; - } + virtual std::string request() { return " Target: The target's behavior."; } }; // ============================================================================================================ @@ -44,32 +46,32 @@ class Target { */ class Adapter : public Target { private: - Adaptee* m_adaptee; + Adaptee* adaptee_; public: - explicit Adapter(Adaptee* adaptee) : m_adaptee{adaptee} { + explicit Adapter(Adaptee* adaptee) : adaptee_{adaptee} { std::cout << "Adapter constructer.\n"; } - std::string request() const override { return m_adaptee->specificRequest(); } + std::string request() override { return adaptee_->specificRequest(); } }; /** * The client code supports all classes that follow the Target interface. */ -namespace Client { -void clientCode(const Target* target) { +namespace client { +void clientCode(Target* const target) { if (target != nullptr) std::cout << "Output: " << target->request() << "\n"; } -} // namespace Client +} // namespace client void run() { std::cout << "Client: Can work just fine with the Target objects:\n"; Target target = Target(); std::cout << "Target: " << target.request() << "\n"; - Client::clientCode(&target); + client::clientCode(&target); std::cout << "\n\n"; std::cout << "Client: Cannot work with the Adaptee objects:\n"; @@ -78,13 +80,13 @@ void run() { // Client::clientCode(&adaptee); // error std::cout << "Client: But can work with it via the Adapter:\n"; - Adapter adapter = Adapter(&adaptee); - Client::clientCode(&adapter); + auto adapter = Adapter(&adaptee); + client::clientCode(&adapter); std::cout << "\n"; } -} // namespace AdapterPattern +} // namespace adapter_pattern -namespace CaseStudy { +namespace case_study { // Target interface expected by the existing system class PaymentSystem { public: @@ -98,26 +100,31 @@ class PaymentSystem { // Adaptee: a new payment API with an incompatible interface class PayPalAPI { public: - static void sendPayment(const std::string& email) { + void sendPayment(const std::string& email) { std::cout << "Payment sent via PayPal to " << email << "\n"; + dummy_++; } + + private: + int dummy_{}; }; // Adapter: makes PayPalAPI compatible with PaymentSystem class PayPalAdapter : public PaymentSystem { private: - PayPalAPI paypal; + PayPalAPI paypal_; public: void payWithCard(const std::string& cardNumber) override { // Treat the cardNumber parameter as a PayPal email - paypal.sendPayment(cardNumber); + paypal_.sendPayment(cardNumber); } }; // Client code: uses the old interface without modification void run() { - std::string method, input; + std::string method; + std::string input; method = std::string("card") + std::string(""); input = "1234-5678-9999"; // method = std::string("paypal") + std::string("");input = @@ -125,21 +132,21 @@ void run() { std::cout << "Choose payment method (card/paypal): " << method << "\n"; - PaymentSystem* paymentSystem = nullptr; + PaymentSystem* payment_system = nullptr; if (method == "card") { - paymentSystem = new PaymentSystem(); - paymentSystem->payWithCard(input); + payment_system = new PaymentSystem(); + payment_system->payWithCard(input); } else if (method == "paypal") { - paymentSystem = new PayPalAdapter(); - paymentSystem->payWithCard(input); + payment_system = new PayPalAdapter(); + payment_system->payWithCard(input); } else { std::cout << "Unsupported payment method!\n"; } - delete paymentSystem; + delete payment_system; } -} // namespace CaseStudy +} // namespace case_study #include "ExampleRegistry.h" @@ -149,8 +156,8 @@ class AdapterExample : public IExample { std::string name() const override { return "Adapter"; } std::string description() const override { return "Factory Pattern Example"; } void execute() override { - AdapterPattern::run(); - CaseStudy::run(); + adapter_pattern::run(); + case_study::run(); } }; diff --git a/src/dp/structural/Bridge.cpp b/src/dp/structural/Bridge.cpp index f54c6d8..65e4437 100644 --- a/src/dp/structural/Bridge.cpp +++ b/src/dp/structural/Bridge.cpp @@ -16,7 +16,7 @@ #include "ExampleRegistry.h" namespace { -namespace Problem { +namespace problem { class Widget { public: virtual ~Widget() = default; @@ -25,9 +25,6 @@ class Widget { /* Concrete variations for Button */ class Button : public Widget { - public: - virtual ~Button() = default; - public: std::string clickOn() const override { return "Click on: Button\n"; } }; @@ -46,9 +43,6 @@ class ButtonLinux : public Button { /* Concrete variations for Label */ class Label : public Widget { - public: - virtual ~Label() = default; - public: std::string clickOn() const override { return "Click on: Label\n"; } }; @@ -69,23 +63,23 @@ class LabelLinux : public Label { * macOS etc*/ // [Problem 1] We have to write the Text/TextLinux ... -namespace Client { +namespace client { void clientCode(const Widget* widget) { if (widget != nullptr) std::cout << widget->clickOn(); } -} // namespace Client +} // namespace client void run() { // [Problem 2] : Use the Bridge if you need to be able to switch // implementations at runtime. how to exmaple for this still don't know Widget* button = new ButtonWindows(); - Client::clientCode(button); + client::clientCode(button); delete button; } -} // namespace Problem +} // namespace problem -namespace BridgePattern { +namespace bridge_pattern { /** * The Implementation defines the interface for all implementation classes. It * doesn't have to match the Abstraction's interface. In fact, the two @@ -116,11 +110,11 @@ class LinuxImplemetation : public OsImplemetation { */ class WidgetAbstraction { protected: - OsImplemetation* _implementation; + OsImplemetation* implementation_; public: explicit WidgetAbstraction(OsImplemetation* implemetation) - : _implementation{implemetation} {} + : implementation_{implemetation} {} virtual ~WidgetAbstraction() = default; virtual std::string clickOn() const = 0; @@ -134,7 +128,7 @@ class ButtonAbstraction : public WidgetAbstraction { explicit ButtonAbstraction(OsImplemetation* implemetation) : WidgetAbstraction{implemetation} {} std::string clickOn() const override { - return this->_implementation->clickOnImplement() + "Click on: Button\n"; + return this->implementation_->clickOnImplement() + "Click on: Button\n"; } }; @@ -143,31 +137,31 @@ class LabelAbstraction : public WidgetAbstraction { explicit LabelAbstraction(OsImplemetation* implemetation) : WidgetAbstraction{implemetation} {} std::string clickOn() const override { - return this->_implementation->clickOnImplement() + "Click on: Label\n"; + return this->implementation_->clickOnImplement() + "Click on: Label\n"; } }; -namespace Client { +namespace client { void clientCode(const WidgetAbstraction* widget) { if (widget != nullptr) std::cout << widget->clickOn(); } -} // namespace Client +} // namespace client void run() { - // TODO: check memory leak here + // TODO(phong-nguyen): check memory leak here OsImplemetation* os = new WindowsImplemetation(); WidgetAbstraction* widget = new ButtonAbstraction(os); - Client::clientCode(widget); + client::clientCode(widget); os = new LinuxImplemetation(); widget = new LabelAbstraction(os); - Client::clientCode(widget); + client::clientCode(widget); delete os; delete widget; } -} // namespace BridgePattern +} // namespace bridge_pattern class BridgeExample : public IExample { public: @@ -175,8 +169,8 @@ class BridgeExample : public IExample { std::string name() const override { return "Bridge"; } std::string description() const override { return "Bridge Pattern Example"; } void execute() override { - Problem::run(); - BridgePattern::run(); + problem::run(); + bridge_pattern::run(); } }; diff --git a/src/dp/structural/Composite.cpp b/src/dp/structural/Composite.cpp index 4b11bdb..4065ea5 100644 --- a/src/dp/structural/Composite.cpp +++ b/src/dp/structural/Composite.cpp @@ -10,48 +10,49 @@ #include #include #include +#include namespace { -namespace Problem { +namespace problem { class File { private: - std::string _name; + std::string name_; public: - explicit File(const std::string& fileName) : _name{fileName} {} - std::string getName() const { return this->_name; } + explicit File(std::string fileName) : name_{std::move(fileName)} {} + std::string getName() const { return this->name_; } - void setName(const std::string& name) { this->_name = name; } + void setName(const std::string& name) { this->name_ = name; } - void open() const { std::cout << "Open file: " << _name << "\n"; } + void open() const { std::cout << "Open file: " << name_ << "\n"; } }; // [P1] Have the NewTypeFile => Update Folder (fields, functions) class Folder { private: - std::string _name; + std::string name_; std::list - _files; // Should store the pointer to the actual file so when we delete + files_; // Should store the pointer to the actual file so when we delete // the file it should delete in the list - std::list _subFolders; + std::list subFolders_; // [P2] What about the parrent ? public: - explicit Folder(const std::string& name) : _name{name} {} + explicit Folder(std::string name) : name_{std::move(name)} {} ~Folder() { - for (File* f : _files) { + for (File* f : files_) { delete f; } - for (Folder* sf : _subFolders) { + for (Folder* sf : subFolders_) { delete sf; } } void removeFile(const File* file) { - _files.remove_if([file](const File* f) { return f == file; }); + files_.remove_if([file](const File* f) { return f == file; }); } void removeFileByName(const std::string& name) { @@ -67,12 +68,12 @@ class Folder { // } auto it = - std::find_if(_files.begin(), _files.end(), + std::find_if(files_.begin(), files_.end(), [&name](const File* f) { return f->getName() == name; }); - if (it != _files.end()) { + if (it != files_.end()) { delete *it; // free the memory - _files.erase(it); // remove the pointer from the list + files_.erase(it); // remove the pointer from the list } } @@ -87,32 +88,32 @@ class Folder { // } // } auto it = - std::find_if(_subFolders.begin(), _subFolders.end(), + std::find_if(subFolders_.begin(), subFolders_.end(), [&name](const Folder* f) { return f->getName() == name; }); - if (it != _subFolders.end()) { + if (it != subFolders_.end()) { delete *it; // free the memory - _subFolders.erase(it); // remove the pointer from the list + subFolders_.erase(it); // remove the pointer from the list } } - void addFile(File* file) { _files.push_back(file); } + void addFile(File* file) { files_.push_back(file); } - void addFolder(Folder* folder) { _subFolders.push_back(folder); } + void addFolder(Folder* folder) { subFolders_.push_back(folder); } void removeFolder(const Folder* folder) { - _subFolders.remove_if([folder](const Folder* f) { return f == folder; }); + subFolders_.remove_if([folder](const Folder* f) { return f == folder; }); } - std::string getName() const { return _name; } + std::string getName() const { return name_; } - void open() const { std::cout << "Open Folder: " << _name << "\n"; } + void open() const { std::cout << "Open Folder: " << name_ << "\n"; } int size() const { - int size = static_cast(_files.size()); + int size = static_cast(files_.size()); // Consider using std::accumulate algorithm instead of a raw loop. - std::for_each(_subFolders.begin(), _subFolders.end(), + std::for_each(subFolders_.begin(), subFolders_.end(), [&size](const Folder* sf) { size += sf->size(); }); // for (const Folder *subFolder : _subFolders) @@ -123,26 +124,26 @@ class Folder { return size; } - const std::list& getSubFolders() const { return _subFolders; } + const std::list& getSubFolders() const { return subFolders_; } - const std::list& getFiles() const { return _files; } + const std::list& getFiles() const { return files_; } void getFilesRecursive(std::list& out) const { - out.insert(out.end(), _files.begin(), _files.end()); - for (const Folder* sf : _subFolders) { + out.insert(out.end(), files_.begin(), files_.end()); + for (const Folder* sf : subFolders_) { sf->getFilesRecursive(out); } } void getSubFoldersRecursive(std::list& out) const { - out.insert(out.end(), _subFolders.begin(), _subFolders.end()); - for (const Folder* sf : _subFolders) { + out.insert(out.end(), subFolders_.begin(), subFolders_.end()); + for (const Folder* sf : subFolders_) { sf->getSubFoldersRecursive(out); } } }; -namespace Client { +namespace client { void clientCode(const Folder* folder) { std::cout << "File name: " << folder->getName() << "\n"; folder->open(); @@ -155,17 +156,17 @@ void clientCode(const Folder* folder) { std::cout << "\t\tFile: " << f->getName() << "\n"; } - std::list subFolders; - folder->getSubFoldersRecursive(subFolders); - for (const Folder* sf : subFolders) { + std::list sub_folders; + folder->getSubFoldersRecursive(sub_folders); + for (const Folder* sf : sub_folders) { std::cout << "\t\tFolder: " << sf->getName() << "\n"; } } -} // namespace Client +} // namespace client void run() { std::cout << "\n\n"; - Folder* root = new Folder("root"); + auto* root = new Folder("root"); root->open(); // Prepare files @@ -176,32 +177,32 @@ void run() { root->addFile(new File(*file2)); root->addFile(new File(*file3)); - Folder* subFolder1 = new Folder("subFolder1"); - Folder* subFolder2 = new Folder("subFolder2"); - Folder* subFolder3 = new Folder("subFolder3"); + auto* sub_folder1 = new Folder("subFolder1"); + auto* sub_folder2 = new Folder("subFolder2"); + auto* sub_folder3 = new Folder("subFolder3"); - root->addFolder(new Folder(*subFolder1)); - root->addFolder(new Folder(*subFolder2)); - root->addFolder(new Folder(*subFolder3)); + root->addFolder(new Folder(*sub_folder1)); + root->addFolder(new Folder(*sub_folder2)); + root->addFolder(new Folder(*sub_folder3)); - Client::clientCode(root); + client::clientCode(root); // Clean up memory - delete subFolder1; - delete subFolder2; - delete subFolder3; + delete sub_folder1; + delete sub_folder2; + delete sub_folder3; delete file1; delete file2; delete file3; root->removeFileByName("fileName1.txt"); - Client::clientCode(root); + client::clientCode(root); delete root; // deletes all files/subfolders inside recursively } -} // namespace Problem +} // namespace problem -namespace CompositePattern { +namespace composite_pattern { /** * Component is the abstraction for leafs and composites. * It defines the interface that must be implemented by the objects in the @@ -210,31 +211,30 @@ namespace CompositePattern { */ class FileSystem { private: - FileSystem* _parent; - std::string _name; + FileSystem* parent_{}; + std::string name_; public: - explicit FileSystem(const std::string& fileName) - : _parent{nullptr}, _name{fileName} {} + explicit FileSystem(std::string fileName) : name_{std::move(fileName)} {} virtual ~FileSystem() { std::cout << "Destructor: " << this->getName() << "\n"; } - FileSystem* getParent() const { return _parent; } + FileSystem* getParent() const { return parent_; } - void setParent(FileSystem* parent) { _parent = parent; } + void setParent(FileSystem* parent) { parent_ = parent; } - std::string getName() const { return this->_name; } + std::string getName() const { return this->name_; } virtual int size() const { return 1; } - void setName(const std::string& name) { this->_name = name; } + void setName(const std::string& name) { this->name_ = name; } - virtual void add(FileSystem* fs) { + virtual void add(FileSystem*) { // do nothing here } - virtual void remove(FileSystem* fs) { + virtual void remove(FileSystem*) { // do nothing here } @@ -257,31 +257,31 @@ class FileSystem { */ class Folder : public FileSystem { private: - std::list _children; + std::list children_; // Remove children [[maybe_unused]] void removeChildren(const FileSystem* file) { - _children.remove_if([file](const FileSystem* f) { return f == file; }); + children_.remove_if([file](const FileSystem* f) { return f == file; }); } [[maybe_unused]] void removeChildrenByName(const std::string& name) { auto it = std::find_if( - _children.begin(), _children.end(), + children_.begin(), children_.end(), [&name](const FileSystem* f) { return f->getName() == name; }); - if (it != _children.end()) { + if (it != children_.end()) { delete *it; // free the memory - _children.erase(it); // remove the pointer from the list + children_.erase(it); // remove the pointer from the list } } [[maybe_unused]] const std::list& getChildren() const { - return _children; + return children_; } void getChildrensRecursive(std::list& out) const { - for (FileSystem* fs : _children) { + for (FileSystem* fs : children_) { if (fs->isComposite()) { const Folder* f = static_cast(fs); if (f != nullptr) @@ -295,9 +295,9 @@ class Folder : public FileSystem { public: explicit Folder(const std::string& name) : FileSystem{name} {} - ~Folder() { + ~Folder() override { // Delete folder should delete all children - for (auto f : _children) { + for (auto* f : children_) { std::cout << "Folder '" << this->getName() << "' deleted : " << f->getName() << "\n"; delete f; @@ -307,14 +307,14 @@ class Folder : public FileSystem { void add(FileSystem* fs) override { std::cout << "Folder '" << this->getName() << "' added : " << fs->getName() << "\n"; - _children.push_back(fs); + children_.push_back(fs); fs->setParent(this); } void remove(FileSystem* fs) override { std::cout << "Folder: " << this->getName() << "removed : " << fs->getName() << "\n"; - _children.remove(fs); + children_.remove(fs); fs->setParent(nullptr); } @@ -323,8 +323,8 @@ class Folder : public FileSystem { } int size() const override { - int size = static_cast(_children.size()); - std::for_each(_children.begin(), _children.end(), [&size](FileSystem* fs) { + int size = static_cast(children_.size()); + std::for_each(children_.begin(), children_.end(), [&size](FileSystem* fs) { if (fs->isComposite()) { const Folder* f = static_cast(fs); if (f != nullptr) @@ -363,28 +363,30 @@ class ZipFile : public FileSystem { class ShortCut : public FileSystem { private: - FileSystem* origin; + FileSystem* origin_; public: - explicit ShortCut(FileSystem* fs) : FileSystem{fs->getName()} { origin = fs; } + explicit ShortCut(FileSystem* fs) : FileSystem{fs->getName()} { + origin_ = fs; + } void open() const override { std::cout << "Open ShortCut: " << this->getName() << "\n"; - if (origin != nullptr) { - std::cout << "Navigate to: " << origin->getName() << "\n"; + if (origin_ != nullptr) { + std::cout << "Navigate to: " << origin_->getName() << "\n"; } else { std::cout << "Original file no longer exist\n"; } } }; -namespace Client { +namespace client { void clientCode(const FileSystem* fs) { std::cout << "File name: " << fs->getName() << ", size: " << fs->size() << "\n"; fs->open(); } -} // namespace Client +} // namespace client void run() { std::cout << "\n\n"; @@ -398,16 +400,16 @@ void run() { root->add(file1); root->add(file2); root->add(file3); - Client::clientCode(file1); - Client::clientCode(root); + client::clientCode(file1); + client::clientCode(root); - Folder* subFolder1 = new Folder("subFolder1"); - Folder* subFolder2 = new Folder("subFolder2"); - Folder* subFolder3 = new Folder("subFolder3"); - root->add(subFolder1); - root->add(subFolder2); - root->add(subFolder3); - Client::clientCode(root); + auto* sub_folder1 = new Folder("subFolder1"); + auto* sub_folder2 = new Folder("subFolder2"); + auto* sub_folder3 = new Folder("subFolder3"); + root->add(sub_folder1); + root->add(sub_folder2); + root->add(sub_folder3); + client::clientCode(root); root->remove(file1); delete file1; @@ -421,7 +423,7 @@ void run() { delete root; // deletes all files/subfolders inside recursively } -} // namespace CompositePattern +} // namespace composite_pattern } // namespace @@ -435,8 +437,8 @@ class CompositeExample : public IExample { return "Composite Pattern Example"; } void execute() override { - Problem::run(); - CompositePattern::run(); + problem::run(); + composite_pattern::run(); } }; diff --git a/src/dp/structural/Decorator.cpp b/src/dp/structural/Decorator.cpp index 675f918..572c448 100644 --- a/src/dp/structural/Decorator.cpp +++ b/src/dp/structural/Decorator.cpp @@ -6,17 +6,15 @@ // (**) when it’s awkward or not possible to extend an object’s behavior using // inheritance. UML: docs/uml/patterns_structural_decorator.drawio.svg -#include #include -#include #include namespace { -namespace Problem { +namespace problem { class IComponent { public: - virtual ~IComponent() {} + virtual ~IComponent() = default; virtual std::string operation() const = 0; }; @@ -50,38 +48,38 @@ class ComponentWithAandB : public ConcreteComponent { // If you have 3 features , e.g FeatureC -> many combinations // If you have 5 features -> 32 subclasses -namespace Client { +namespace client { void clientCode(const IComponent& comp) { std::cout << comp.operation() << "\n"; } -} // namespace Client +} // namespace client void run() { std::cout << "\n\nProblem\n"; IComponent* simple = new ConcreteComponent; - Client::clientCode(*simple); + client::clientCode(*simple); - IComponent* withA = new ComponentWithA; - Client::clientCode(*withA); + IComponent* with_a = new ComponentWithA; + client::clientCode(*with_a); - IComponent* withB = new ComponentWithB; - Client::clientCode(*withB); + IComponent* with_b = new ComponentWithB; + client::clientCode(*with_b); - IComponent* withAB = new ComponentWithAandB; - Client::clientCode(*withAB); + IComponent* with_ab = new ComponentWithAandB; + client::clientCode(*with_ab); delete simple; - delete withA; - delete withB; - delete withAB; + delete with_a; + delete with_b; + delete with_ab; } -} // namespace Problem +} // namespace problem -namespace DecoratorPattern { +namespace decorator_pattern { class IComponent { public: - virtual ~IComponent() {} + virtual ~IComponent() = default; virtual std::string operation() const = 0; }; @@ -104,15 +102,15 @@ class ConcreteComponent : public IComponent { */ class BaseDecorator : public IComponent { protected: - IComponent* m_component; + IComponent* component_; public: - explicit BaseDecorator(IComponent* component) : m_component{component} {} + explicit BaseDecorator(IComponent* component) : component_{component} {} /** * The Decorator delegates all work to the wrapped component. */ - std::string operation() const override { return m_component->operation(); } + std::string operation() const override { return component_->operation(); } }; /** @@ -152,36 +150,36 @@ class ConcreteDecoratorC : public BaseDecorator { } }; -namespace Client { +namespace client { void clientCode(const IComponent& comp) { std::cout << comp.operation() << "\n"; } -} // namespace Client +} // namespace client void run() { std::cout << "\n\nDecorator\n"; IComponent* simple = new ConcreteComponent; - Client::clientCode(*simple); + client::clientCode(*simple); - IComponent* withA = new ConcreteDecoratorA(simple); - Client::clientCode(*withA); + IComponent* with_a = new ConcreteDecoratorA(simple); + client::clientCode(*with_a); - IComponent* withB = new ConcreteDecoratorB(simple); - Client::clientCode(*withB); + IComponent* with_b = new ConcreteDecoratorB(simple); + client::clientCode(*with_b); - IComponent* withAB = new ConcreteDecoratorB(withA); - Client::clientCode(*withAB); + IComponent* with_ab = new ConcreteDecoratorB(with_a); + client::clientCode(*with_ab); - IComponent* withABC = new ConcreteDecoratorC(withAB); - Client::clientCode(*withABC); + IComponent* with_abc = new ConcreteDecoratorC(with_ab); + client::clientCode(*with_abc); delete simple; - delete withA; - delete withB; - delete withAB; - delete withABC; + delete with_a; + delete with_b; + delete with_ab; + delete with_abc; } -} // namespace DecoratorPattern +} // namespace decorator_pattern } // namespace @@ -195,8 +193,8 @@ class DecoratorExample : public IExample { return "Decorator Pattern Example"; } void execute() override { - Problem::run(); - DecoratorPattern::run(); + problem::run(); + decorator_pattern::run(); } }; diff --git a/src/dp/structural/Facade.cpp b/src/dp/structural/Facade.cpp index a5f9b6e..dc37cca 100644 --- a/src/dp/structural/Facade.cpp +++ b/src/dp/structural/Facade.cpp @@ -10,39 +10,61 @@ #include namespace { -namespace Problem { +namespace problem { class AuthSubSystem { public: virtual ~AuthSubSystem() = default; - void login() const { std::cout << "AuthSubSystem: login\n"; } + void login() { + std::cout << "AuthSubSystem: login\n"; + dummy_++; + } + + private: + int dummy_{}; }; class ValidatorSubSystem { public: virtual ~ValidatorSubSystem() = default; - virtual void check() const { + virtual void check() { std::cout << "ValidatorSubSystem: check input\n"; + dummy_++; } + + private: + int dummy_{}; }; class LoggerSubSystem { public: virtual ~LoggerSubSystem() = default; - void write() const { std::cout << "LoggerSubSystem: write log\n"; } + void write() { + std::cout << "LoggerSubSystem: write log\n"; + dummy_++; + } + + private: + int dummy_{}; }; class BackendSubSystem { public: virtual ~BackendSubSystem() = default; - void send() const { std::cout << "BackendSubSystem: send request\n"; } + void send() { + std::cout << "BackendSubSystem: send request\n"; + dummy_++; + } + + private: + int dummy_{}; }; -namespace Client1 { +namespace client1 { // The client must manually interact with each subsystem. // This creates unnecessary complexity. -void clientCode(const ValidatorSubSystem& s1, const AuthSubSystem& s2, - const LoggerSubSystem& s3, const BackendSubSystem& s4) { +void clientCode(ValidatorSubSystem& s1, AuthSubSystem& s2, LoggerSubSystem& s3, + BackendSubSystem& s4) { s1.check(); s2.login(); s3.write(); @@ -53,15 +75,15 @@ void clientCode(const ValidatorSubSystem& s1, const AuthSubSystem& s2, // - combine subsystem operations // - manage lifecycle and error handling } -} // namespace Client1 +} // namespace client1 -namespace Client2 { +namespace client2 { // The client must manually interact with each subsystem. // This creates unnecessary complexity. -void clientCode(const ValidatorSubSystem& s1) { +void clientCode(ValidatorSubSystem& s1) { s1.check(); } -} // namespace Client2 +} // namespace client2 void run() { std::cout << "\n\nProblem\n"; @@ -71,29 +93,47 @@ void run() { LoggerSubSystem l; BackendSubSystem b; - Client1::clientCode(v, a, l, b); - Client2::clientCode(v); + client1::clientCode(v, a, l, b); + client2::clientCode(v); } -} // namespace Problem +} // namespace problem -namespace Facade { +namespace facade { class AuthSubSystem { public: virtual ~AuthSubSystem() = default; - void login() const { std::cout << "AuthSubSystem: login\n"; } + void login() { + std::cout << "AuthSubSystem: login\n"; + dummy_++; + } + + private: + int dummy_{}; }; class ValidatorSubSystem { public: virtual ~ValidatorSubSystem() = default; - void check() const { std::cout << "ValidatorSubSystem: check input\n"; } + void check() { + std::cout << "ValidatorSubSystem: check input\n"; + dummy_++; + } + + private: + int dummy_{}; }; class LoggerSubSystem { public: virtual ~LoggerSubSystem() = default; - void write() const { std::cout << "LoggerSubSystem: write log\n"; } + void write() { + std::cout << "LoggerSubSystem: write log\n"; + dummy_++; + } + + private: + int dummy_{}; }; class BackendSubSystem { @@ -119,10 +159,10 @@ class MockBackendSubSystem : public BackendSubSystem { */ class RequestFacade { protected: - const AuthSubSystem* auth_; - const ValidatorSubSystem* validator_; - const LoggerSubSystem* logger_; - const BackendSubSystem* backend_; + AuthSubSystem* auth_; + ValidatorSubSystem* validator_; + LoggerSubSystem* logger_; + BackendSubSystem* backend_; /** * Depending on your application's needs, you can provide the Facade with @@ -132,14 +172,14 @@ class RequestFacade { /** * In this case we will delegate the memory ownership to Facade Class */ - explicit RequestFacade(const AuthSubSystem* s1 = nullptr, - const ValidatorSubSystem* s2 = nullptr, - const LoggerSubSystem* s3 = nullptr, - const BackendSubSystem* s4 = nullptr) { - this->auth_ = s1 ?: new AuthSubSystem; - this->validator_ = s2 ?: new ValidatorSubSystem; - this->logger_ = s3 ?: new LoggerSubSystem; - this->backend_ = s4 ?: new BackendSubSystem; + explicit RequestFacade(AuthSubSystem* s1 = nullptr, + ValidatorSubSystem* s2 = nullptr, + LoggerSubSystem* s3 = nullptr, + BackendSubSystem* s4 = nullptr) { + this->auth_ = s1 ? s1 : new AuthSubSystem(); + this->validator_ = s2 ? s2 : new ValidatorSubSystem(); + this->logger_ = s3 ? s3 : new LoggerSubSystem(); + this->backend_ = s4 ? s4 : new BackendSubSystem(); } ~RequestFacade() { @@ -154,59 +194,59 @@ class RequestFacade { * functionality of the subsystems. However, clients get only to a fraction of * a subsystem's capabilities. */ - void sendRequest() const { + void sendRequest() { validator_->check(); auth_->login(); logger_->write(); backend_->send(); } - void validate() const { validator_->check(); } + void validate() { validator_->check(); } }; -namespace Client1 { +namespace client1 { /** * The client code works with complex subsystems through a simple interface * provided by the Facade. When a facade manages the lifecycle of the subsystem, * the client might not even know about the existence of the subsystem. This * approach lets you keep the complexity under control. */ -void clientCode(const RequestFacade& facade) { +void clientCode(RequestFacade& facade) { facade.sendRequest(); } -} // namespace Client1 +} // namespace client1 -namespace Client2 { +namespace client2 { /** * The client code works with complex subsystems through a simple interface * provided by the Facade. When a facade manages the lifecycle of the subsystem, * the client might not even know about the existence of the subsystem. This * approach lets you keep the complexity under control. */ -void clientCode(const RequestFacade& facade) { +void clientCode(RequestFacade& facade) { facade.validate(); } -} // namespace Client2 +} // namespace client2 void run() { std::cout << "\n\nFacade\n"; { - RequestFacade* facade = new RequestFacade(); - Client1::clientCode(*facade); - Client2::clientCode(*facade); + auto* facade = new RequestFacade(); + client1::clientCode(*facade); + client2::clientCode(*facade); delete facade; } { // injected subsystems for mocktest std::cout << "\n"; - const MockBackendSubSystem* b = new MockBackendSubSystem(); - RequestFacade* facade = new RequestFacade(nullptr, nullptr, nullptr, b); - Client1::clientCode(*facade); + auto* b = new MockBackendSubSystem(); + auto* facade = new RequestFacade(nullptr, nullptr, nullptr, b); + client1::clientCode(*facade); delete facade; } } -} // namespace Facade +} // namespace facade } // namespace #include "ExampleRegistry.h" @@ -217,8 +257,8 @@ class FacadeExample : public IExample { std::string name() const override { return "Facade"; } std::string description() const override { return "Facade Pattern Example"; } void execute() override { - Problem::run(); - Facade::run(); + problem::run(); + facade::run(); } }; diff --git a/src/dp/structural/Flyweight.cpp b/src/dp/structural/Flyweight.cpp index 94a1caa..aace603 100644 --- a/src/dp/structural/Flyweight.cpp +++ b/src/dp/structural/Flyweight.cpp @@ -12,9 +12,10 @@ #include #include #include +#include namespace { -namespace Problem { +namespace problem { class ImageContext { protected: private: @@ -52,9 +53,9 @@ class ImageContext { public: // Role of five // CONSTRUCTOR - explicit ImageContext(const std::string& fileName, int w = 8, int h = 8, + explicit ImageContext(std::string fileName, int w = 8, int h = 8, int dpi = 96, float scale = 1, float opacity = 1) - : fileName_{fileName}, + : fileName_{std::move(fileName)}, width_{w}, height_{h}, dpi_{dpi}, @@ -90,20 +91,20 @@ class ImageContext { } }; -namespace Client { +namespace client { void clientCode(const ImageContext* img) { img->display(); } -} // namespace Client +} // namespace client void run() { std::cout << "\n\nProblem\n"; - ImageContext** imgs = new ImageContext*[5]; + auto** imgs = new ImageContext*[5]; for (int i = 0; i < 5; i++) { imgs[i] = new ImageContext("img1.svg"); - imgs[i]->setOpacity(1 - (float)1 / (i + 1)); - imgs[i]->setScale((float)1 / (i + 1)); - Client::clientCode(imgs[i]); + imgs[i]->setOpacity(1 - static_cast(1) / (i + 1)); + imgs[i]->setScale(static_cast(1) / (i + 1)); + client::clientCode(imgs[i]); } // delete objects first @@ -115,9 +116,9 @@ void run() { delete[] imgs; std::cout << "Size of objects: " << sizeof(ImageContext) * 5 << "\n"; } -} // namespace Problem +} // namespace problem -namespace FlyweightPattern { +namespace flyweight_pattern { /** * The Flyweight stores a common portion of the state (also called intrinsic @@ -152,9 +153,9 @@ class ImageFlyweight { } public: - explicit ImageFlyweight(const std::string& fileName, int w = 8, int h = 8, + explicit ImageFlyweight(std::string fileName, int w = 8, int h = 8, int dpi = 96) - : fileName_{fileName}, + : fileName_{std::move(fileName)}, width_{w}, height_{h}, dpi_{dpi}, @@ -242,7 +243,7 @@ class ImageFlyweight { class ImageFlyweightFactory { private: std::unordered_map - m_imageFlyweights; // unordered_map => need to role of five + imageFlyweights_; // unordered_map => need to role of five static std::string getKey(const std::string& name, int w, int h, int dpi) { return "key_" + name + std::to_string(w * h * dpi); } @@ -252,15 +253,15 @@ class ImageFlyweightFactory { int h = 8, int dpi = 96) { std::string key = getKey(fileName, w, h, dpi); std::cout << "Key: " << key << "\n"; - if (this->m_imageFlyweights.find(key) == this->m_imageFlyweights.end()) { + if (this->imageFlyweights_.find(key) == this->imageFlyweights_.end()) { std::cout << "ImageFlyweightFactory: Can't find a image flyweight, " "creating new one.\n"; - this->m_imageFlyweights.insert( + this->imageFlyweights_.insert( std::make_pair(key, ImageFlyweight(fileName, w, h, dpi))); } else { std::cout << "ImageFlyweightFactory: Reusing existing image flyweight.\n"; } - return this->m_imageFlyweights.at(key); + return this->imageFlyweights_.at(key); } }; @@ -273,13 +274,13 @@ class ImageContext { private: float scale_; float opacity_; - ImageFlyweight* m_flyweight; + ImageFlyweight* flyweight_; public: ImageContext(ImageFlyweight& imageFlyweight, const float& s, const float& o) - : scale_{s}, opacity_{o}, m_flyweight{&imageFlyweight} {} + : scale_{s}, opacity_{o}, flyweight_{&imageFlyweight} {} - void display() const { this->m_flyweight->display(scale_, opacity_); } + void display() const { this->flyweight_->display(scale_, opacity_); } }; /** @@ -288,31 +289,31 @@ class ImageContext { * configured at runtime by passing some contextual data into parameters of its * methods. */ -namespace Client { +namespace client { void clientCode(const ImageContext* img) { img->display(); } -} // namespace Client +} // namespace client void run() { std::cout << "\n\nFlyweight\n"; // Regis the images to the factory - ImageFlyweightFactory* imageRegister = new ImageFlyweightFactory(); - ImageContext* img1 = - new ImageContext(imageRegister->getImangeFlyweight("img1.svg"), 1, 0.1); - Client::clientCode(img1); - ImageContext* img2 = - new ImageContext(imageRegister->getImangeFlyweight("img1.svg"), 1, 0.2); - Client::clientCode(img2); - ImageContext* img3 = - new ImageContext(imageRegister->getImangeFlyweight("img1.svg"), 1, 0.3); - Client::clientCode(img3); - ImageContext* img4 = - new ImageContext(imageRegister->getImangeFlyweight("img1.svg"), 1, 0.4); - Client::clientCode(img4); - ImageContext* img5 = - new ImageContext(imageRegister->getImangeFlyweight("img1.svg"), 1, 0.5); - Client::clientCode(img5); + auto* image_register = new ImageFlyweightFactory(); + auto* img1 = + new ImageContext(image_register->getImangeFlyweight("img1.svg"), 1, 0.1); + client::clientCode(img1); + auto* img2 = + new ImageContext(image_register->getImangeFlyweight("img1.svg"), 1, 0.2); + client::clientCode(img2); + auto* img3 = + new ImageContext(image_register->getImangeFlyweight("img1.svg"), 1, 0.3); + client::clientCode(img3); + auto* img4 = + new ImageContext(image_register->getImangeFlyweight("img1.svg"), 1, 0.4); + client::clientCode(img4); + auto* img5 = + new ImageContext(image_register->getImangeFlyweight("img1.svg"), 1, 0.5); + client::clientCode(img5); std::cout << "Size of objects: " << sizeof(ImageFlyweightFactory) + sizeof(ImageContext) * 5 << "\n"; @@ -321,10 +322,10 @@ void run() { delete img3; delete img4; delete img5; - delete imageRegister; + delete image_register; } -} // namespace FlyweightPattern +} // namespace flyweight_pattern } // namespace #include "ExampleRegistry.h" @@ -337,8 +338,8 @@ class FlyweightExample : public IExample { return "Flyweight Pattern Example"; } void execute() override { - Problem::run(); - FlyweightPattern::run(); + problem::run(); + flyweight_pattern::run(); } }; diff --git a/src/dp/structural/Proxy.cpp b/src/dp/structural/Proxy.cpp index 9c77a20..816d5a0 100644 --- a/src/dp/structural/Proxy.cpp +++ b/src/dp/structural/Proxy.cpp @@ -15,12 +15,13 @@ // UML: docs/uml/patterns_structural_proxy.drawio.svg #include +#include #include "ExampleRegistry.h" namespace { -namespace Problem { -const std::string admin = "admin"; +namespace problem { +const std::string kAdmin = "admin"; class IServer { public: @@ -32,42 +33,42 @@ class IServer { class Server : public IServer { private: - std::string _id; + std::string id_; public: - explicit Server(const std::string& id) : _id{id} { + explicit Server(std::string id) : id_{std::move(id)} { // [P1] Heavy or complex construction, so ideally should be lazy-loaded - std::cout << "[Server] Constructor: " << _id << "\n"; + std::cout << "[Server] Constructor: " << id_ << "\n"; } // [P2] Need access control // [P3] Need to log requests without modifying the Server itself void request1() override { - if (_id != admin) { - std::cout << "[Server] Invalid ID: " << _id << "\n"; + if (id_ != kAdmin) { + std::cout << "[Server] Invalid ID: " << id_ << "\n"; return; } - std::cout << "[Server] Handling request-1 for: " << _id << "\n"; + std::cout << "[Server] Handling request-1 for: " << id_ << "\n"; } void request2() override { - if (_id != admin) { - std::cout << "[Server] Invalid ID: " << _id << "\n"; + if (id_ != kAdmin) { + std::cout << "[Server] Invalid ID: " << id_ << "\n"; return; } - std::cout << "[Server] Handling request-2 for: " << _id << "\n"; + std::cout << "[Server] Handling request-2 for: " << id_ << "\n"; } void request3() override { - if (_id != admin) { - std::cout << "[Server] Invalid ID: " << _id << "\n"; + if (id_ != kAdmin) { + std::cout << "[Server] Invalid ID: " << id_ << "\n"; return; } - std::cout << "[Server] Handling request-3 for: " << _id << "\n"; + std::cout << "[Server] Handling request-3 for: " << id_ << "\n"; } }; -namespace Client { +namespace client { void clientCode(IServer* s) { if (s != nullptr) { s->request1(); @@ -75,33 +76,33 @@ void clientCode(IServer* s) { s->request3(); } } -} // namespace Client +} // namespace client void run() { std::cout << "\n\n"; { - std::string connectionId = "admin"; + std::string connection_id = "admin"; // [P4] The Server is constructed immediately even if we do not call any // requests - IServer* server = new Server(connectionId); + IServer* server = new Server(connection_id); std::cout << "User request\n"; - Client::clientCode(server); + client::clientCode(server); delete server; } { // [P4] Server is constructed even for invalid ID, wasting resources - std::string invalidId = "xxx"; - Server* server = new Server(invalidId); - Client::clientCode(server); + std::string invalid_id = "xxx"; + auto* server = new Server(invalid_id); + client::clientCode(server); delete server; } } -} // namespace Problem +} // namespace problem -namespace ProxyPattern { -const std::string admin = "admin"; +namespace proxy_pattern { +const std::string kAdmin = "admin"; class IServer { public: @@ -113,83 +114,82 @@ class IServer { class Server : public IServer { private: - std::string _id; + std::string id_; public: - explicit Server(const std::string& id) : _id{id} { - std::cout << "[Server] Constructor: " << _id << "\n"; + explicit Server(std::string id) : id_{std::move(id)} { + std::cout << "[Server] Constructor: " << id_ << "\n"; } void request1() override { - std::cout << "[Server] Handling request-1 for: " << _id << "\n"; + std::cout << "[Server] Handling request-1 for: " << id_ << "\n"; } void request2() override { - std::cout << "[Server] Handling request-2 for: " << _id << "\n"; + std::cout << "[Server] Handling request-2 for: " << id_ << "\n"; } void request3() override { - std::cout << "[Server] Handling request-3 for: " << _id << "\n"; + std::cout << "[Server] Handling request-3 for: " << id_ << "\n"; } }; class ServerProxy : public IServer { private: - std::string _id; - Server* _server; + std::string id_; + Server* server_{}; bool checkAccess() { std::cout << "[Proxy] Checking access before forwarding request.\n"; - if (_id != admin) { + if (id_ != kAdmin) { return false; } // Lazy initialization: construct Server only on first access - if (_server == nullptr) { - _server = new Server(_id); + if (server_ == nullptr) { + server_ = new Server(id_); } return true; } void logAccess() const { - std::cout << "[Proxy] Logging request time: " << _id << " .\n"; + std::cout << "[Proxy] Logging request time: " << id_ << " .\n"; } public: - explicit ServerProxy(const std::string& id) : _id{id}, _server{nullptr} { - std::cout << "[Proxy] Constructor: " << _id << "\n"; + explicit ServerProxy(std::string id) : id_{std::move(id)} { + std::cout << "[Proxy] Constructor: " << id_ << "\n"; } - ~ServerProxy() { - std::cout << "[Proxy] Destructor: " << _id << "\n"; - if (_server != nullptr) { - delete _server; - } + ~ServerProxy() override { + std::cout << "[Proxy] Destructor: " << id_ << "\n"; + + delete server_; } void request1() override { if (checkAccess()) { - _server->request1(); + server_->request1(); logAccess(); } } void request2() override { if (checkAccess()) { - _server->request2(); + server_->request2(); logAccess(); } } void request3() override { if (checkAccess()) { - _server->request3(); + server_->request3(); logAccess(); } } }; -namespace Client { +namespace client { void clientCode(IServer* s) { if (s != nullptr) { s->request1(); @@ -197,27 +197,27 @@ void clientCode(IServer* s) { s->request3(); } } -} // namespace Client +} // namespace client void run() { std::cout << "\n\n"; { - std::string connectionId = "admin"; + std::string connection_id = "admin"; // Server is not constructed until first request is made - IServer* server = new ServerProxy(connectionId); + IServer* server = new ServerProxy(connection_id); std::cout << "User request\n"; - Client::clientCode(server); + client::clientCode(server); delete server; } // Server is not constructed if id is invalid - std::string invalidId = "xxx"; - Server* server = new Server(invalidId); - Client::clientCode(server); + std::string invalid_id = "xxx"; + auto* server = new Server(invalid_id); + client::clientCode(server); delete server; } -} // namespace ProxyPattern +} // namespace proxy_pattern class ProxyExample : public IExample { public: @@ -225,8 +225,8 @@ class ProxyExample : public IExample { std::string name() const override { return "Proxy"; } std::string description() const override { return "Proxy Pattern Example"; } void execute() override { - Problem::run(); - ProxyPattern::run(); + problem::run(); + proxy_pattern::run(); } }; diff --git a/src/exercise/CMakeLists.txt b/src/exercise/CMakeLists.txt deleted file mode 100644 index 6a72978..0000000 --- a/src/exercise/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(EXCERCISE_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/DriverAccount.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/DriverStudentManager.cpp -) - -set(EXCERCISE_SOURCES ${EXCERCISE_SOURCES} PARENT_SCOPE) - -add_subdirectory(account) -add_subdirectory(student_manager) \ No newline at end of file diff --git a/src/exercise/DriverAccount.cpp b/src/exercise/DriverAccount.cpp deleted file mode 100644 index e5cbc5a..0000000 --- a/src/exercise/DriverAccount.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include - -#include "Account.h" -#include "ExampleRegistry.h" - -namespace { -void driver_test_account() { - std::cout << "\n====================\n" - << __func__ << "\n" - << "====================\n\n"; - - Account acc{0.0}; - while (true) { - std::cout << "=== MENU ===\n"; - std::cout << "1. Deposit\n"; - std::cout << "2. Withdraw\n"; - std::cout << "3. View balance\n"; - std::cout << "4. View transactions\n"; - std::cout << "5. Quit\n"; - - std::cout << "Input the choice: "; - int choice{}; - if (!(std::cin >> choice) || choice < 1 || choice > 5) { - std::cout << ">> " << "Invalid the choice\n"; - std::cin.clear(); - std::cin.ignore(std::numeric_limits::max(), '\n'); - continue; - }; - - double amount{}; - if (choice == 1) { - std::cout << "Input the amount: "; - if (std::cin >> amount) { - try { - acc.credit(amount); - } catch (std::invalid_argument& e) { - std::cout << ">> " << e.what() << "\n"; - } - } else { - std::cout << ">> Invalid the amount\n"; - } - } else if (choice == 2) { - std::cout << "Input the amount: "; - if (std::cin >> amount) { - try { - acc.debit(amount); - } catch (std::invalid_argument& e) { - std::cout << ">> " << e.what() << "\n"; - } - } else { - std::cout << ">> Invalid the amount\n"; - } - } else if (choice == 3) { - std::cout << ">>" << acc.toString() << "\n"; - } else if (choice == 4) { - std::cout << ">> "; - acc.viewLog(); - std::cout << "\n"; - } else { - return; - } - } -} -} // namespace - -class DriverAccount : public IExample { - public: - std::string group() const override { return "exercise"; }; - std::string name() const override { return "DriverAccount"; } - std::string description() const override { return "Test Account"; } - - void execute() override { driver_test_account(); } -}; - -REGISTER_EXAMPLE(DriverAccount, "exercise", "DriverAccount") \ No newline at end of file diff --git a/src/exercise/DriverStudentManager.cpp b/src/exercise/DriverStudentManager.cpp deleted file mode 100644 index 37f2bd1..0000000 --- a/src/exercise/DriverStudentManager.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include "ExampleRegistry.h" - -#include "Manager.h" - -namespace { -void driver_test_student_manager() { - std::cout << "\n====================\n" - << __func__ << "\n" - << "====================\n\n"; - Manager m; - char c; - - while (true) { - std::cout << "\n---------- MENU ----------\n"; - std::cout << "C Create a student\n"; - std::cout << "R Retrieve a student\n"; - std::cout << "U Update a student\n"; - std::cout << "D Delete a student\n"; - std::cout << "S Show student list\n"; - std::cout << "Q Quit\n"; - std::cout << "--------------------------\n"; - - std::cout << "Your choice: "; - std::cin >> c; - std::cin.ignore(); - - c = std::toupper(c); - - if (c == 'Q') - break; - - switch (c) { - case 'C': - m.add(); - break; - - case 'R': { - auto r = m.findByName(); - for (auto s : r) - std::cout << *s << "\n"; - break; - } - - case 'U': - m.update(); - break; - case 'D': - m.remove(); - break; - case 'S': - std::cout << m; - break; - } - } - - std::cout << "Bye bye!\n"; -} -} // namespace - -class DriverStudentManager : public IExample { - public: - std::string group() const override { return "excercise"; }; - std::string name() const override { return "DriverStudentManager"; } - std::string description() const override { return "Test StudentManager"; } - - void execute() override { driver_test_student_manager(); } -}; - -REGISTER_EXAMPLE(DriverStudentManager, "exercise", "DriverStudentManager") \ No newline at end of file diff --git a/src/exercise/account/Account.cpp b/src/exercise/account/Account.cpp deleted file mode 100644 index 762b2ad..0000000 --- a/src/exercise/account/Account.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "Account.h" -#include -#include -#include -#include - -Account::Account(double init) : balance_{init} { - if (init < 0) { - throw std::invalid_argument("Invalid credit amount\n"); - } -} - -double Account::getBalance() const { - return balance_; -} - -void Account::credit(double amount) { - if (amount < 0) { - throw std::invalid_argument("Invalid credit amount\n"); - } - balance_ += amount; - - std::ostringstream oss; - std::time_t now = time(NULL); - oss << std::fixed << std::setprecision(4) << "[credit] " << amount << " at " - << time2Str(now); - log_.push_back(oss.str()); -} - -void Account::debit(double amount) { - if (amount < 0) { - throw std::invalid_argument("Invalid debit amount\n"); - } - - double debit_amount = std::min(balance_, amount); - balance_ -= debit_amount; - - std::ostringstream oss; - std::time_t now = time(NULL); - oss << std::fixed << std::setprecision(4) << "[debit] " << debit_amount - << " at " << time2Str(now); - log_.push_back(oss.str()); -} - -void Account::viewLog() const { - if (log_.empty()) { - std::cout << "No transactions found.\n"; - return; - } - for (const auto& m : log_) { - std::cout << m << '\n'; - } -} - -std::string Account::toString() const { - std::ostringstream oss; - oss << std::fixed << std::setprecision(4) << "Account balance: " << balance_; - return oss.str(); -} - -const std::string Account::time2Str(time_t t) { - std::string time = ctime(&t); - time.pop_back(); // remove newline - return time; -} \ No newline at end of file diff --git a/src/exercise/account/Account.h b/src/exercise/account/Account.h deleted file mode 100644 index 1bda25f..0000000 --- a/src/exercise/account/Account.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include -#include -#include - -class Account { - public: - explicit Account(double init = 0.0); - double getBalance() const; - - void credit(double amount); - void debit(double amount); - void viewLog() const; - std::string toString() const; - - private: - static const std::string time2Str(time_t t); - - private: - double balance_; - std::vector log_; -}; diff --git a/src/exercise/account/CMakeLists.txt b/src/exercise/account/CMakeLists.txt deleted file mode 100644 index 8fea504..0000000 --- a/src/exercise/account/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_library(ex_account) - -target_sources(ex_account - PRIVATE - Account.cpp - PUBLIC - FILE_SET HEADERS - FILES - Account.h -) \ No newline at end of file diff --git a/src/exercise/student_manager/CMakeLists.txt b/src/exercise/student_manager/CMakeLists.txt deleted file mode 100644 index 52ea98b..0000000 --- a/src/exercise/student_manager/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -add_library(ex_student_manager) - -target_include_directories(ex_student_manager - PRIVATE - ${PROJECT_SOURCE_DIR}/include -) - -target_sources(ex_student_manager - PRIVATE - Student.cpp - Manager.cpp - PUBLIC - FILE_SET HEADERS - FILES - Manager.h -) \ No newline at end of file diff --git a/src/exercise/student_manager/Manager.cpp b/src/exercise/student_manager/Manager.cpp deleted file mode 100644 index 7e03f4f..0000000 --- a/src/exercise/student_manager/Manager.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "Manager.h" -#include -#include -#include - -Manager::~Manager() { - for (auto it : students_) { - delete it; - } -} - -void Manager::add() { - std::string name = inputStr("Name?", "Invalid"); - std::string address = inputStr("Address?", "Invalid"); - Student* s = new Student(name, address); - students_.push_back(s); - sortByName(); - std::cout << "Add successful!\n"; -} - -void Manager::remove() { - std::string code = inputStr("Code?", "Invalid"); - // for (auto it = students_.begin(); it != students_.end(); ++it) { - // if ((*it)->getCode().substr(0, code.size()) == code) { - // delete *it; - // students_.erase(it); - // std::cout << "Remove successfull!\n"; - // break; - // } - // } - auto it = std::find_if( - students_.begin(), students_.end(), - [&code](const Student* s) { return s && s->getCode().find(code) == 0; }); - - if (it != students_.end()) { - students_.erase(it); - std::cout << "Remove successfull!\n"; - } - - std::cout << "Student not found!\n"; -} - -void Manager::update() { - std::string code = inputStr("Code?", "Invalid"); - auto* s = findByCode(code); - if (s != nullptr) { - std::cout << "Hint: use old value, press Enter\n"; - std::string name = inputStr("New Name?", "Invalid"); - std::string address = inputStr("New Address?", "Invalid"); - std::string markStr = inputStr("New Mark?", "Invalid"); - double mark{}; - try { - mark = std::stod(markStr); - } catch (std::exception& e) { - std::cout << "invalid mark" << e.what(); - } - if (mark < 0.0 || mark > 10.0) { - std::cout << "invalid mark " << mark << "\n"; - return; - } - - s->setMark(mark); - s->setName(name); - s->setAddress(address); - std::cout << "Update successful! \n"; - } -} - -std::ostream& operator<<(std::ostream& os, const Manager& manager) { - for (const auto* const s : manager.students_) { - os << *s << "\n"; - } - return os; -} - -Student* Manager::findByCode(const std::string& cod) { - // for (auto it : students_) { - // // if (it->getCode().substr(0, cod.size()) == cod) // partial match - // if (it->getCode() == cod) { - // return it; - // } - // } - const auto it = std::find_if( - students_.begin(), students_.end(), - [&cod](const Student* s) { return s && s->getCode() == cod; }); - - if (it != students_.end()) { - return *it; - } - - std::cout << "Student not found !!\n"; - return nullptr; -} - -void Manager::sortByName() { - std::sort(students_.begin(), students_.end(), - [](const Student* a, const Student* b) { return *a < *b; }); -} - -std::string Manager::trim(const std::string& str) { - constexpr std::string_view whitespaces{" \n\r\t\v\x00"}; - auto firstPos = str.find_first_not_of(whitespaces); - if (firstPos == std::string::npos) { - return ""; - } - - auto secondPos = str.find_last_not_of(whitespaces); - return str.substr(firstPos, secondPos - firstPos + 1); -} - -std::vector Manager::findByName() { - std::string name = inputStr("Name?", "Invalid Name?"); - std::vector result; - // for (auto it : students_) { - // // contain - // if (it->getName().find(name) != std::string::npos) { - // result.push_back(it); - // } - // } - std::copy_if(students_.begin(), students_.end(), std::back_inserter(result), - [&name](const Student* const s) { - return s && s->getName().find(name) != std::string::npos; - }); - - return result; -} - -std::string Manager::inputStr(const std::string& prompt, - const std::string& error) { - std::string output; - std::cout << prompt << "\n"; - while (true) { - if (!std::getline(std::cin, output)) { - std::cout << "getline failed\n"; - return ""; - } - - output = trim(output); - if (output != "") { - return output; - } - std::cout << error; - } -} \ No newline at end of file diff --git a/src/exercise/student_manager/Manager.h b/src/exercise/student_manager/Manager.h deleted file mode 100644 index 258fd6c..0000000 --- a/src/exercise/student_manager/Manager.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include -#include "Student.h" -class Manager { - public: - ~Manager(); - - void add(); - void update(); - void remove(); - std::vector findByName(); - - private: - void sortByName(); - Student* findByCode(const std::string& cod); - static std::string trim(const std::string& str); - static std::string inputStr(const std::string& prompt, const std::string& error); - - friend std::ostream& operator<<(std::ostream& os, const Manager& manager); - - private: - std::vector students_; -}; \ No newline at end of file diff --git a/src/exercise/student_manager/Student.cpp b/src/exercise/student_manager/Student.cpp deleted file mode 100644 index abbaa3e..0000000 --- a/src/exercise/student_manager/Student.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "Student.h" -#include -#include - -Student::Student(const std::string& name, const std::string& address) - : code_{}, name_{name}, address_{address}, mark_{0.0} { - setCode(); -} - -Student::~Student(){ - -} - -Student::Student(const Student& other) - : code_{other.code_}, - name_{other.name_}, - address_{other.address_}, - mark_{other.mark_} {} - -void Student::setCode() { - // get name code XXX - std::string nameCode = name_; - - name_.append(3, ' '); // so, name code at least 3 charactor - nameCode.resize(3); - std::replace(nameCode.begin(), nameCode.end(), ' ', 'X'); - std::transform(nameCode.begin(), nameCode.end(), nameCode.begin(), ::toupper); - - // get time code XXXX - time_t now = time(NULL); - std::string timeCode = std::to_string(now); - timeCode = timeCode.substr(timeCode.size() - 3, timeCode.size()); - code_ = nameCode + timeCode; -} - -std::ostream& operator<<(std::ostream& os, const Student& student) { - os << "[" << student.code_ << "] " << student.name_ << " " << student.mark_; - return os; -} - -bool operator<(const Student& a, const Student& b) { - if (a.name_ != b.name_) { - return a.name_ < b.name_; - }; - return a.code_ < b.code_; -} - -void Student::setName(const std::string& name) { - name_ = name; -} - -void Student::setAddress(const std::string& address) { - address_ = address; -} - -void Student::setMark(double mark) { - mark_ = mark; -} - -const std::string& Student::getAddress() const{ - return address_; -} - -const std::string& Student::getCode() const { - return code_; -} - -const std::string& Student::getName() const { - return name_; -} - -double Student::getMark() const { - return mark_; -} diff --git a/src/exercise/student_manager/Student.h b/src/exercise/student_manager/Student.h deleted file mode 100644 index 76d4053..0000000 --- a/src/exercise/student_manager/Student.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include -class Student { - - public: - Student(const std::string& name, const std::string& address); - Student(const Student& other); - ~Student(); - - void setName(const std::string& name); - void setAddress(const std::string& address); - void setMark(double mark); - - const std::string& getCode() const; - const std::string& getAddress() const; - const std::string& getName() const; - double getMark() const; - - friend std::ostream& operator<<(std::ostream& os, const Student& student); - friend bool operator<(const Student& a, const Student& b); - - private: - void setCode(); - - private: - std::string code_; - std::string name_; - std::string address_; - double mark_; -}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b1b0512..a177103 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -47,7 +48,9 @@ void runMenu() { // sort std::sort(groups.begin(), groups.end()); for (const auto& group : groups) { - std::cout << g_index++ << ". " << group << "\n"; + std::cout + << std::setw(2) << g_index++ << ". " << group + << "\n"; // use at least 2 characters of space for the next value } std::cout << g_index << ". Exit\n"; std::cout << "----------------------------------------\n"; @@ -64,44 +67,47 @@ void runMenu() { continue; } - try { - // Sub-group - const auto& selected_group = groups[g_choice - 1]; - const auto& examples = data.at(selected_group); - - int e_index = 1; - std::vector names; - - for (const auto& [name, _] : examples) { - std::cout << e_index++ << ". " << name << "\n"; - names.push_back(name); - } - std::cout << e_index << ". Back\n"; - std::cout << "----------------------------------------\n"; - std::cout << "Enter choice: "; - - int e_choice = readChoice(); - if (e_choice == e_index) { - continue; - } - - if (e_choice < 1 || e_choice > e_index) { - std::cout << "Invalid example choice\n"; - continue; - } - - auto example = registry.create(selected_group, names[e_choice - 1]); - if (example != nullptr) { - std::cout << "\n--- Running Example [" << example->name() << "] [" - << example->description() << "]---\n\n"; - example->execute(); - std::cout << "\n--- Finished ---\n"; - std::cout << "Press any key to continue ...\n"; - std::cin.get(); + while (true) { + try { + // Sub-group + const auto& selected_group = groups[g_choice - 1]; + const auto& examples = data.at(selected_group); + + int e_index = 1; + std::vector names; + + for (const auto& [name, _] : examples) { + std::cout << std::setw(2) << e_index++ << ". " << name << "\n"; + names.push_back(name); + } + std::cout << std::setw(2) << e_index << ". Back\n"; + std::cout << "----------------------------------------\n"; + std::cout << "Enter choice: "; + + int e_choice = readChoice(); + // return + if (e_choice == e_index) { + break; + } + + if (e_choice < 1 || e_choice > e_index) { + std::cout << "Invalid example choice\n"; + continue; + } + + auto example = registry.create(selected_group, names[e_choice - 1]); + if (example != nullptr) { + std::cout << "\n--- Running Example [" << example->name() << "] [" + << example->description() << "]---\n\n"; + example->execute(); + std::cout << "\n--- Finished ---\n"; + std::cout << "Press any key to continue ...\n"; + std::cin.get(); + } + } catch (std::out_of_range& e) { + std::cout << "\nError" << e.what(); + std::cout << "\nInvalid example. Try again.\n"; } - } catch (std::out_of_range& e) { - std::cout << "\nError" << e.what(); - std::cout << "\nInvalid example. Try again.\n"; } } } diff --git a/src/socket/multiple_client/MultiTCPServer.cpp b/src/socket/multiple_client/MultiTCPServer.cpp index cdefcbc..7eae0d5 100644 --- a/src/socket/multiple_client/MultiTCPServer.cpp +++ b/src/socket/multiple_client/MultiTCPServer.cpp @@ -5,7 +5,7 @@ #include // close(server) #include -#include +#include "ExampleRegistry.h" void MultiTCPServer::acceptLoop() { while (isRunning()) { diff --git a/src/socket/multiple_client/MultiTCPServer.h b/src/socket/multiple_client/MultiTCPServer.h index 3be1ad4..5e1c870 100644 --- a/src/socket/multiple_client/MultiTCPServer.h +++ b/src/socket/multiple_client/MultiTCPServer.h @@ -1,17 +1,17 @@ #pragma once #include #include -#include "ExampleRegistry.h" #include "../simple_tcp/TCPServer.h" +#include "IExample.h" class MultiTCPServer : public TCPServer, public IExample { public: std::string group() const override { return "socket/tcp"; } - std::string name() const override { return "SimpleTCPServer"; } + std::string name() const override { return "MultiTCPServer"; } std::string description() const override { - return "Simple TCP server listening on port 8080.\nRun `telnet localhost " + return "Multi TCP server listening on port 8080.\nRun `telnet localhost " "8080` to connect."; } diff --git a/src/socket/simple_tcp/SimpleTCPClient.cpp b/src/socket/simple_tcp/SimpleTCPClient.cpp index ff2acc1..7705605 100644 --- a/src/socket/simple_tcp/SimpleTCPClient.cpp +++ b/src/socket/simple_tcp/SimpleTCPClient.cpp @@ -1,5 +1,4 @@ #include -#include #include "ExampleRegistry.h" #include "TCPClient.h" @@ -24,7 +23,7 @@ void run() { break; }; - // TODO: why we need \n here + // TODO(phong-nguyen): why we need \n here client.send(msg + "\n"); response = client.receive(); std::cout << response; diff --git a/src/socket/simple_tcp/TCPClient.cpp b/src/socket/simple_tcp/TCPClient.cpp index c517989..c993289 100644 --- a/src/socket/simple_tcp/TCPClient.cpp +++ b/src/socket/simple_tcp/TCPClient.cpp @@ -17,23 +17,23 @@ bool TCPClient::connect() { } // specifying the address - sockaddr_in serverAddress{}; - serverAddress.sin_family = AF_INET; - serverAddress.sin_port = htons(port_); + sockaddr_in server_address{}; + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port_); // serverAddress.sin_addr.s_addr = INADDR_ANY; - if (::inet_pton(AF_INET, host_.c_str(), &serverAddress.sin_addr) <= 0) { + if (::inet_pton(AF_INET, host_.c_str(), &server_address.sin_addr) <= 0) { throw std::runtime_error("invalid address"); } // sending connection request return ( ::connect(client_fd_, - reinterpret_cast(&serverAddress), // global syscall - sizeof(serverAddress)) == 0); + reinterpret_cast(&server_address), // global syscall + sizeof(server_address)) == 0); } -void TCPClient::send(const std::string& msg) { +void TCPClient::send(const std::string& msg) const { if (client_fd_ < 0) { throw std::runtime_error("socket not connected"); } @@ -50,7 +50,7 @@ void TCPClient::send(const std::string& msg) { } } -std::string TCPClient::receive() { +std::string TCPClient::receive() const { if (client_fd_ < 0) { throw std::runtime_error("socket not connected"); } diff --git a/src/socket/simple_tcp/TCPClient.h b/src/socket/simple_tcp/TCPClient.h index 5ddd62c..61b4900 100644 --- a/src/socket/simple_tcp/TCPClient.h +++ b/src/socket/simple_tcp/TCPClient.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include class TCPClient { @@ -8,11 +8,12 @@ class TCPClient { bool connect(); void close(); - void send(const std::string& msg); - std::string receive(); + void send(const std::string& msg) const; + std::string receive() const; const std::string& getHost() const; - uint16_t getPort() const; + uint16_t getPort() const; + private: std::string host_; uint16_t port_; diff --git a/src/socket/simple_tcp/TCPServer.cpp b/src/socket/simple_tcp/TCPServer.cpp index 6ba5efe..1a3848a 100644 --- a/src/socket/simple_tcp/TCPServer.cpp +++ b/src/socket/simple_tcp/TCPServer.cpp @@ -5,11 +5,8 @@ #include // close(server) #include -#include -#include -TCPServer::TCPServer(uint16_t port) - : port_{port}, server_fd_{-1}, running_{false} {} +TCPServer::TCPServer(uint16_t port) : port_{port} {} TCPServer::~TCPServer() { if (server_fd_ >= 0) { @@ -33,7 +30,7 @@ void TCPServer::createSocket() { } } -void TCPServer::bindSocket() { +void TCPServer::bindSocket() const { sockaddr_in server_addr{}; server_addr.sin_family = AF_INET; // IPv4 // server_addr.sin_addr.s_addr = INADDR_ANY; // accept connections on all network interfaces @@ -51,14 +48,14 @@ void TCPServer::bindSocket() { if (bind(server_fd_, reinterpret_cast(&server_addr), sizeof(server_addr)) < 0) { throw std::runtime_error( - "bind failed"); // TODO: anyway to know what kind of the error + "bind failed"); // TODO(phong-nguyen): anyway to know what kind of the error } std::cout << "Server running on " << inet_ntoa(server_addr.sin_addr) << ":" << ntohs(server_addr.sin_port) << "\n"; } -void TCPServer::listenSocket() { +void TCPServer::listenSocket() const { // (128) is the maximum number of queued connection requests if (listen(server_fd_, 128) < 0) { throw std::runtime_error("listen failed"); @@ -104,7 +101,7 @@ void TCPServer::sendAll(int fd, const char* data, size_t len) { } } -void TCPServer::handleClient(int client_fd) { +void TCPServer::handleClient(int client_fd) const { char buffer[1024]; // send a notify to the client diff --git a/src/socket/simple_tcp/TCPServer.h b/src/socket/simple_tcp/TCPServer.h index 2f8c107..c32eaf9 100644 --- a/src/socket/simple_tcp/TCPServer.h +++ b/src/socket/simple_tcp/TCPServer.h @@ -1,7 +1,5 @@ #pragma once -#include -#include -#include +#include class TCPServer { public: @@ -23,14 +21,14 @@ class TCPServer { /** * @brief Bind the socket to a port and network interface */ - void bindSocket(); + void bindSocket() const; /** * @brief Put the socket into listening mode */ - void listenSocket(); + void listenSocket() const; - static void sendAll(int fd, const char* data, size_t len); + static void sendAll(int fd, const char* data, std::size_t len); protected: /** @@ -39,7 +37,7 @@ class TCPServer { * @param * [in] client_fd client file descriptor */ - void handleClient(int client_fd); + void handleClient(int client_fd) const; /** * @brief Loop waiting for client connections