From b7d9eb04c1c92cf424d1e246645c745cee872330 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Mon, 11 May 2026 13:37:09 +0700 Subject: [PATCH 01/18] refactor --- src/dp/behavioral/Command.cpp | 29 ++++----- src/dp/creational/Prototype.cpp | 66 ++++++++++---------- src/dp/structural/Adapter.cpp | 66 +++++++++----------- src/dp/structural/Bridge.cpp | 107 +++++++++++++++++--------------- 4 files changed, 135 insertions(+), 133 deletions(-) diff --git a/src/dp/behavioral/Command.cpp b/src/dp/behavioral/Command.cpp index f72c3f6..a6a2bfb 100644 --- a/src/dp/behavioral/Command.cpp +++ b/src/dp/behavioral/Command.cpp @@ -11,9 +11,9 @@ // UML: docs/uml/patterns_behavioral_command.drawio.svg -#include #include #include +#include "Logger.h" namespace { namespace command { @@ -37,17 +37,17 @@ class ICommand { class Receiver { public: void doCheck() { - std::cout << "Receiver checking... \n"; + LOG("Receiver checking... "); dummy_++; }; void doInit() { - std::cout << "Receiver initializing... \n"; + LOG("Receiver initializing... "); dummy_++; }; void doLaunch(const std::string& arg) { - std::cout << "Receiver launching... \n\t" << arg << "\n"; + LOG("Receiver launching... \n\t" + arg); dummy_++; }; @@ -63,7 +63,7 @@ class Receiver { */ class SimpleConcreteCommand : public ICommand { public: - void execute() const override { std::cout << "\t SimpleCommand executed \n"; } + void execute() const override { LOG("executed"); } }; class ComplexConcreteCommand : public ICommand { @@ -76,7 +76,7 @@ class ComplexConcreteCommand : public ICommand { : receiver_{receiver}, payload_{std::move(payload)} {}; void execute() const override { - std::cout << "\t ComplexCommand executed \n"; + LOG("executed"); this->receiver_->doCheck(); this->receiver_->doInit(); this->receiver_->doLaunch(payload_); @@ -109,6 +109,7 @@ class Invoker { void setOnFinish(ICommand* command) { this->on_finish_ = command; } void invoke() const { + LOG("executed"); if (on_start_ != nullptr) { on_start_->execute(); } @@ -119,20 +120,20 @@ class Invoker { } }; -namespace client { -void clientCode(const Invoker* invoker) { - invoker->invoke(); -} - -} // namespace client - void run() { + auto client_code = [](const Invoker* invoker) { + invoker->invoke(); + }; + + // Receiver: UI auto* ui = new Receiver(); + // How to execute these command when something triggered auto* invoker = new Invoker(); invoker->setOnStart(new SimpleConcreteCommand()); invoker->setOnFinish(new ComplexConcreteCommand(ui, "cmd --version")); - client::clientCode(invoker); + + client_code(invoker); delete ui; } } // namespace command diff --git a/src/dp/creational/Prototype.cpp b/src/dp/creational/Prototype.cpp index fc74230..5cb57bd 100644 --- a/src/dp/creational/Prototype.cpp +++ b/src/dp/creational/Prototype.cpp @@ -7,12 +7,15 @@ // UML: docs/uml/patterns_behavioral_prototype.drawio.svg -#include #include #include +#include "Logger.h" namespace { namespace prototy { +constexpr std::string_view kLoggerEtxId = "logger"; +constexpr std::string_view kAnalyzeId = "analyze"; + /* * Prototype interface declares the cloning methods. * In most cases, it’s a single `clone` method. @@ -32,17 +35,15 @@ class IExtensionPrototype { */ class LoggerExtension : public IExtensionPrototype { private: - std::string logLevel_; + std::string log_level_; public: explicit LoggerExtension(std::string level = "DEBUG") - : logLevel_{std::move(level)} {} + : log_level_{std::move(level)} {} IExtensionPrototype* clone() override { return new LoggerExtension(*this); } - void execute() const override { - std::cout << "[Logger] log level: " << logLevel_ << "\n"; - } + void execute() const override { LOG("log level: " + log_level_); } }; class AnalyticsExtension : public IExtensionPrototype { @@ -56,9 +57,7 @@ class AnalyticsExtension : public IExtensionPrototype { return new AnalyticsExtension(*this); } - void execute() const override { - std::cout << "[Analytics] sampling rate: " << sRate_ << "\n"; - } + void execute() const override { LOG_S("sampling rate: " << sRate_); } }; /** @@ -78,12 +77,14 @@ class ExtensionPrototypeRegistry { it = prototypes_.erase(it); // erase and move to next } } - void registerExtension(const std::string& id, IExtensionPrototype* proto) { - prototypes_[id] = proto; + void register_extension(const std::string_view& id, + IExtensionPrototype* proto) { + LOG(id); + prototypes_[std::string(id)] = proto; } - IExtensionPrototype* create(const std::string& id) const { - auto it = prototypes_.find(id); + IExtensionPrototype* create(const std::string_view& id) const { + auto it = prototypes_.find(std::string(id)); if (it != prototypes_.end()) { return it->second->clone(); } @@ -91,27 +92,28 @@ class ExtensionPrototypeRegistry { } }; -/* - * Client creates a new object by asking a prototype to clone itself - */ -namespace client { -void clientCode(const ExtensionPrototypeRegistry* const registry) { - IExtensionPrototype* logger_etx = registry->create("logger"); - logger_etx->execute(); - IExtensionPrototype* analyx_etx = registry->create("analyze"); - analyx_etx->execute(); - - delete logger_etx; - delete analyx_etx; -} - -} // namespace client - void run() { + // Client creates a new object by asking a prototype to clone itself + auto client_code = [](const ExtensionPrototypeRegistry* const registry) { + IExtensionPrototype* logger_etx = registry->create(prototy::kLoggerEtxId); + logger_etx->execute(); + IExtensionPrototype* analyx_etx = registry->create(prototy::kAnalyzeId); + analyx_etx->execute(); + + delete logger_etx; + delete analyx_etx; + }; + + // Create a registry auto* registry = new ExtensionPrototypeRegistry(); - registry->registerExtension("logger", new LoggerExtension("DEBUG")); - registry->registerExtension("analyze", new AnalyticsExtension(1200)); - client::clientCode(registry); + + // Register extensions + registry->register_extension(prototy::kLoggerEtxId, + new LoggerExtension("DEBUG")); + registry->register_extension(prototy::kAnalyzeId, + new AnalyticsExtension(1200)); + + client_code(registry); delete registry; } diff --git a/src/dp/structural/Adapter.cpp b/src/dp/structural/Adapter.cpp index d4619f7..6ea3755 100644 --- a/src/dp/structural/Adapter.cpp +++ b/src/dp/structural/Adapter.cpp @@ -7,7 +7,7 @@ // UML: docs/uml/patterns_structural_adapter.drawio.svg -#include +#include "Logger.h" namespace adapter_pattern { /** @@ -17,9 +17,9 @@ namespace adapter_pattern { */ class Adaptee { public: - std::string specificRequest() { + void specific_request() { dummy_++; - return "Adaptee: The adaptee's behavior."; + LOG("executed"); } private: @@ -31,7 +31,7 @@ class Adaptee { */ class Target { public: - virtual std::string request() { return " Target: The target's behavior."; } + virtual void request() { LOG("executed"); } }; // ============================================================================================================ @@ -49,40 +49,31 @@ class Adapter : public Target { Adaptee* adaptee_; public: - explicit Adapter(Adaptee* adaptee) : adaptee_{adaptee} { - std::cout << "Adapter constructer.\n"; - } + explicit Adapter(Adaptee* adaptee) : adaptee_{adaptee} { LOG("constructed"); } - std::string request() override { return adaptee_->specificRequest(); } + void request() override { return adaptee_->specific_request(); } }; -/** - * The client code supports all classes that follow the Target interface. - */ +void run() { + LOG("Adapter Example"); -namespace client { -void clientCode(Target* const target) { - if (target != nullptr) - std::cout << "Output: " << target->request() << "\n"; -} -} // namespace client + // The client code supports all classes that follow the Target interface. + auto client_code = [](Target* target) { + LOG("executed"); + target->request(); + }; -void run() { - std::cout << "Client: Can work just fine with the Target objects:\n"; + LOG("Client: Can work just fine with the Target objects:"); Target target = Target(); - std::cout << "Target: " << target.request() << "\n"; - client::clientCode(&target); - std::cout << "\n\n"; + client_code(&target); - std::cout << "Client: Cannot work with the Adaptee objects:\n"; + LOG("Client: Cannot work with the Adaptee objects:"); Adaptee adaptee = Adaptee(); - std::cout << "Adaptee: " << adaptee.specificRequest() << "\n"; // Client::clientCode(&adaptee); // error - std::cout << "Client: But can work with it via the Adapter:\n"; + LOG("Client: But can work with it via the Adapter:"); auto adapter = Adapter(&adaptee); - client::clientCode(&adapter); - std::cout << "\n"; + client_code(&adapter); } } // namespace adapter_pattern @@ -90,8 +81,8 @@ namespace case_study { // Target interface expected by the existing system class PaymentSystem { public: - virtual void payWithCard(const std::string& cardNumber) { - std::cout << "Payment using card: " << cardNumber << "\n"; + virtual void pay_with_card(const std::string& card_number) { + LOG_S("Payment using card: " << card_number); } virtual ~PaymentSystem() = default; @@ -100,8 +91,8 @@ class PaymentSystem { // Adaptee: a new payment API with an incompatible interface class PayPalAPI { public: - void sendPayment(const std::string& email) { - std::cout << "Payment sent via PayPal to " << email << "\n"; + void send_payment(const std::string& email) { + LOG_S("Payment sent via PayPal to " << email); dummy_++; } @@ -115,14 +106,15 @@ class PayPalAdapter : public PaymentSystem { PayPalAPI paypal_; public: - void payWithCard(const std::string& cardNumber) override { + void pay_with_card(const std::string& cardNumber) override { // Treat the cardNumber parameter as a PayPal email - paypal_.sendPayment(cardNumber); + paypal_.send_payment(cardNumber); } }; // Client code: uses the old interface without modification void run() { + LOG("Case Study Example"); std::string method; std::string input; method = std::string("card") + std::string(""); @@ -130,18 +122,18 @@ void run() { // method = std::string("paypal") + std::string("");input = // "user@example.com"; - std::cout << "Choose payment method (card/paypal): " << method << "\n"; + LOG_S("Choose payment method (card/paypal): " << method); PaymentSystem* payment_system = nullptr; if (method == "card") { payment_system = new PaymentSystem(); - payment_system->payWithCard(input); + payment_system->pay_with_card(input); } else if (method == "paypal") { payment_system = new PayPalAdapter(); - payment_system->payWithCard(input); + payment_system->pay_with_card(input); } else { - std::cout << "Unsupported payment method!\n"; + LOG("Unsupported payment method!"); } delete payment_system; diff --git a/src/dp/structural/Bridge.cpp b/src/dp/structural/Bridge.cpp index 7998e47..bceb942 100644 --- a/src/dp/structural/Bridge.cpp +++ b/src/dp/structural/Bridge.cpp @@ -11,70 +11,77 @@ // UML: docs/uml/patterns_structural_bridge.drawio.svg -#include - +#include +#include #include "ExampleRegistry.h" +#include "Logger.h" namespace { namespace problem { class Widget { public: virtual ~Widget() = default; - virtual std::string clickOn() const = 0; + virtual void click_on() const = 0; }; /* Concrete variations for Button */ class Button : public Widget { public: - std::string clickOn() const override { return "Click on: Button\n"; } + void click_on() const override { LOG("executed"); } }; class ButtonWindows : public Button { public: - std::string clickOn() const override { return "[Linux]" + Button::clickOn(); } + void click_on() const override { + LOG("executed"); + Button::click_on(); + } }; class ButtonLinux : public Button { public: - std::string clickOn() const override { - return "[Windows]" + Button::clickOn(); + void click_on() const override { + LOG("executed"); + Button::click_on(); } }; /* Concrete variations for Label */ class Label : public Widget { public: - std::string clickOn() const override { return "Click on: Label\n"; } + void click_on() const override { LOG("executed"); } }; class LabelWindows : public Label { public: - std::string clickOn() const override { - return "[Windows]" + Label::clickOn(); + void click_on() const override { + LOG("executed"); + Label::click_on(); } }; class LabelLinux : public Label { public: - std::string clickOn() const override { return "[Linux]" + Label::clickOn(); } + void click_on() const override { + LOG("executed"); + Label::click_on(); + } }; -/* Concrete variations for others widgets like Text,CCombo or new platform +void run() { + LOG("Problem"); + /* Concrete variations for others widgets like Text,CCombo or new platform * macOS etc*/ -// [Problem 1] We have to write the Text/TextLinux ... + // [Problem 1] We have to write the Text/TextLinux ... + auto client_code = [](const Widget* widget) { + if (widget != nullptr) + widget->click_on(); + }; -namespace client { -void clientCode(const Widget* widget) { - if (widget != nullptr) - std::cout << widget->clickOn(); -} -} // 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_code(button); delete button; } } // namespace problem @@ -89,18 +96,18 @@ namespace bridge_pattern { */ class OsImplemetation { public: - virtual std::string clickOnImplement() const = 0; + virtual void click_on_ipl() const = 0; virtual ~OsImplemetation() = default; }; class WindowsImplemetation : public OsImplemetation { public: - std::string clickOnImplement() const override { return "[Windows]"; } + void click_on_ipl() const override { LOG("[Windows]"); } }; class LinuxImplemetation : public OsImplemetation { public: - std::string clickOnImplement() const override { return "[Linux]"; } + void click_on_ipl() const override { LOG("[Linux]"); } }; /** @@ -110,14 +117,14 @@ class LinuxImplemetation : public OsImplemetation { */ class WidgetAbstraction { protected: - OsImplemetation* implementation_; + std::shared_ptr implementation_; public: - explicit WidgetAbstraction(OsImplemetation* implemetation) - : implementation_{implemetation} {} + explicit WidgetAbstraction(std::shared_ptr implemetation) + : implementation_{std::move(implemetation)} {} virtual ~WidgetAbstraction() = default; - virtual std::string clickOn() const = 0; + virtual void click_on() const = 0; }; /** @@ -125,40 +132,40 @@ class WidgetAbstraction { */ class ButtonAbstraction : public WidgetAbstraction { public: - explicit ButtonAbstraction(OsImplemetation* implemetation) - : WidgetAbstraction{implemetation} {} - std::string clickOn() const override { - return this->implementation_->clickOnImplement() + "Click on: Button\n"; + explicit ButtonAbstraction(std::shared_ptr implemetation) + : WidgetAbstraction{std::move(implemetation)} {} + void click_on() const override { + LOG("executed"); + this->implementation_->click_on_ipl(); } }; class LabelAbstraction : public WidgetAbstraction { public: - explicit LabelAbstraction(OsImplemetation* implemetation) - : WidgetAbstraction{implemetation} {} - std::string clickOn() const override { - return this->implementation_->clickOnImplement() + "Click on: Label\n"; + explicit LabelAbstraction(std::shared_ptr implemetation) + : WidgetAbstraction{std::move(implemetation)} {} + void click_on() const override { + LOG("executed"); + this->implementation_->click_on_ipl(); } }; -namespace client { -void clientCode(const WidgetAbstraction* widget) { - if (widget != nullptr) - std::cout << widget->clickOn(); -} -} // namespace client - void run() { - // TODO(phong-nguyen): check memory leak here - OsImplemetation* os = new WindowsImplemetation(); + LOG("Bridge Example"); + auto client_code = [](const WidgetAbstraction* widget) { + if (widget != nullptr) + widget->click_on(); + }; + + std::shared_ptr os = + std::make_shared(); WidgetAbstraction* widget = new ButtonAbstraction(os); - client::clientCode(widget); + client_code(widget); - os = new LinuxImplemetation(); + os = std::make_shared(); widget = new LabelAbstraction(os); - client::clientCode(widget); + client_code(widget); - delete os; delete widget; } } // namespace bridge_pattern From 8b7932b576126c37138844660dd5c0a1dd2630fc Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 24 May 2026 12:16:31 +0700 Subject: [PATCH 02/18] Typo fix --- src/core/concurrency/ConditionVariable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/concurrency/ConditionVariable.cpp b/src/core/concurrency/ConditionVariable.cpp index 80bbf2f..05cfe3d 100644 --- a/src/core/concurrency/ConditionVariable.cpp +++ b/src/core/concurrency/ConditionVariable.cpp @@ -25,7 +25,7 @@ void worker_thread() { // The thread continues only when 'ready' becomes true. cv.wait(lock, []() { return ready; }); - LOG("Proccessing data"); + LOG("Processing data"); data += " after processing"; finish = true; From 996f70ee516ac5f6047ea2355dcfd2131eb43b9f Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 24 May 2026 12:16:43 +0700 Subject: [PATCH 03/18] Update --- src/core/basics/ControlFlow.cpp | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/core/basics/ControlFlow.cpp b/src/core/basics/ControlFlow.cpp index fd381ef..d46440c 100644 --- a/src/core/basics/ControlFlow.cpp +++ b/src/core/basics/ControlFlow.cpp @@ -1,47 +1,47 @@ -#include #include "ExampleRegistry.h" +#include "Logger.h" namespace { void conditionals() { - std::cout << "\n--- Conditional Examples ---\n"; + LOG("Conditional Examples"); // if-else int x = rand(); - std::cout << "x = " << x << "\n"; + LOG_S("x = " << x); if (x > 0) { - std::cout << "x is positive\n"; + LOG("x is positive"); } else if (x < 0) { - std::cout << "x is negative\n"; + LOG("x is negative"); } else { - std::cout << "x is zero\n"; + LOG("x is zero"); } // switch int choice = rand() % 2 + 1; - std::cout << "choice = " << x << "\n"; + LOG_S("Choice = " << std::to_string(x)); switch (choice) { case 1: - std::cout << "Choice is 1\n"; + LOG("Choice is 1"); break; case 2: - std::cout << "Choice is 2\n"; + LOG("Choice is 2"); break; default: - std::cout << "Choice is something else\n"; + LOG("Choice is something else"); break; } } void jumps() { - std::cout << "\n--- Jump Statement Examples ---\n"; + LOG("Jump Statement Examples"); // goto int num = rand(); if (num == 3) goto jumpLabel; - std::cout << "This line will be skipped.\n"; + LOG("This line will be skipped."); jumpLabel: - std::cout << "Jumped here using goto!\n"; + LOG("Jumped here using goto!"); // 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 - std::cout << "i = " << i << "\n"; + LOG_S("i = " << i); } } @@ -59,43 +59,43 @@ int square(int n) { } void functionCalls() { - std::cout << "\n--- Function Call Examples ---\n"; + LOG("Function Call Examples"); // function call int result = square(5); - std::cout << "square(5) = " << result << "\n"; + LOG_S("square(5) = " << result); } void loops() { - std::cout << "\n--- Loop Examples ---\n"; + LOG("Loop Examples"); // while int i = 0; while (i < 3) { - std::cout << "while loop i = " << i << "\n"; + LOG_S("while loop i = " << i); ++i; } // do-while int j = 0; do { - std::cout << "do-while loop j = " << j << "\n"; + LOG_S("do-while loop j = " << j); ++j; } while (j < 2); // for(initialization; condition; update) for (int k = 0; k < 3; ++k) { - std::cout << "for loop k = " << k << "\n"; + LOG_S("for loop k = " << k); } // ranged-for const int arr[] = {10, 20, 30}; for (int value : arr) { - std::cout << "ranged-for value = " << value << "\n"; + LOG_S("ranged-for value = " << value); } } void halts() { - std::cout << "\n--- Halt Examples ---\n"; + LOG("Halt Examples"); // std::exit() — terminates the program normally // std::abort() — terminates abnormally (no cleanup) @@ -106,13 +106,13 @@ void halts() { } void exceptions() { - std::cout << "\n--- Exception Handling Examples ---\n"; + LOG("Exception Handling Examples"); // try - catch - throw try { throw std::runtime_error("Something went wrong!"); } catch (const std::exception& e) { - std::cout << "Caught exception: " << e.what() << "\n"; + LOG_S("Caught exception: " << e.what()); } } } // namespace From 32e41da69e410798f8b8506592244d20d111cf51 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 24 May 2026 12:47:41 +0700 Subject: [PATCH 04/18] Add an example for --- src/core/CMakeLists.txt | 1 + src/core/concurrency/README.md | 9 ++++++++- src/core/concurrency/Timing.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/core/concurrency/Timing.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 57ca20c..a60525a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -97,6 +97,7 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/concurrency/RaceCondition.cpp ${CMAKE_CURRENT_SOURCE_DIR}/concurrency/ConditionVariable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/concurrency/FuturePromise.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/concurrency/Timing.cpp # Utils ${CMAKE_CURRENT_SOURCE_DIR}/utils/Algorithm.cpp diff --git a/src/core/concurrency/README.md b/src/core/concurrency/README.md index 537416f..8237806 100644 --- a/src/core/concurrency/README.md +++ b/src/core/concurrency/README.md @@ -227,4 +227,11 @@ auto future = std::async(std::launch::async, SomeFunctionObject(), arg_1); // Lambda function auto future = std::async(std::launch::async, [](){}); -``` \ No newline at end of file +``` + +## 4. Date and time library +- The `chrono` (since c++11) library defines several main types as well as utility functions and common typedefs: + - clocks + - time points + - durations + - calender/timezone (c++ 20); \ No newline at end of file diff --git a/src/core/concurrency/Timing.cpp b/src/core/concurrency/Timing.cpp new file mode 100644 index 0000000..f8b6582 --- /dev/null +++ b/src/core/concurrency/Timing.cpp @@ -0,0 +1,28 @@ +#include +#include "ExampleRegistry.h" +#include "Logger.h" + +#include + +void run() { + const auto start = std::chrono::steady_clock::now(); + std::this_thread::sleep_for(std::chrono::seconds(5)); + const auto finished = std::chrono::steady_clock::now(); + + const std::chrono::duration elapsed = + finished - start; // default unit is second + LOG_S("Elapsed time: " << elapsed); +} + +class Timing : public IExample { + public: + std::string group() const override { return "core/concurrency"; } + std::string name() const override { return "Timing"; } + std::string description() const override { + return "The examples for code timing"; + } + + void execute() override { run(); } +}; + +REGISTER_EXAMPLE(Timing); \ No newline at end of file From 12a7435cb2432d25753684fa79a4e9e54ce96bb4 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 24 May 2026 16:11:14 +0700 Subject: [PATCH 05/18] Update --- src/core/basics/ControlFlow.cpp | 2 +- src/core/basics/InitializeVariable.cpp | 13 +- src/core/basics/Operations.cpp | 82 +++-- src/core/basics/README.md | 426 ++++++++++++++++++++++--- src/core/basics/TypeQualifier.cpp | 67 ++-- src/core/class/RoleOfThreeFiveZero.cpp | 2 +- 6 files changed, 469 insertions(+), 123 deletions(-) diff --git a/src/core/basics/ControlFlow.cpp b/src/core/basics/ControlFlow.cpp index d46440c..5fca0c7 100644 --- a/src/core/basics/ControlFlow.cpp +++ b/src/core/basics/ControlFlow.cpp @@ -119,7 +119,7 @@ void exceptions() { class ControlFlow : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/basics"; } std::string name() const override { return "ControlFlow"; } std::string description() const override { return "ControlFlow"; } void execute() override { diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp index 33df35a..57c5163 100644 --- a/src/core/basics/InitializeVariable.cpp +++ b/src/core/basics/InitializeVariable.cpp @@ -1,38 +1,39 @@ // cppcheck-suppress-file [unreadVariable, unusedVariable, functionStatic] -#include +#include "Logger.h" #include "ExampleRegistry.h" void initialize_variable(); class InitializeVariable : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/basics"; } std::string name() const override { return "InitializeVariable"; } std::string description() const override { return "InitializeVariable"; } + void execute() override { initialize_variable(); } }; REGISTER_EXAMPLE(InitializeVariable); struct Foo { - Foo() { std::cout << "Default constructor/ default init\n"; } + Foo() { LOG("Default constructor/ default init"); } // Foo(int) explicit Foo(int) { - std::cout << "Constructor called with int / copy init\n"; + LOG( "Constructor called with int / copy init"); } Foo(const Foo& other) { other.dump(); - std::cout << "Copy constructor called\n"; + LOG( "Copy constructor called"); } void dump() const {} }; void initialize_variable() { - std::cout << "\n--- Variable Initialization Examples ---\n"; + LOG( "\n--- Variable Initialization Examples ---"); // * 1) Default-initialization int init_default_var; Foo init_default_obj; diff --git a/src/core/basics/Operations.cpp b/src/core/basics/Operations.cpp index 1eea0c3..b393c8d 100644 --- a/src/core/basics/Operations.cpp +++ b/src/core/basics/Operations.cpp @@ -1,7 +1,7 @@ -#include #include #include "ExampleRegistry.h" +#include "Logger.h" void arithmeticOperator(); void logicalOperator(); @@ -9,7 +9,7 @@ void bitWiseOperator(); class Operations : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/basics"; } std::string name() const override { return "Operations"; } std::string description() const override { return "Operation"; } void execute() override { @@ -22,107 +22,105 @@ class Operations : public IExample { REGISTER_EXAMPLE(Operations); void arithmeticOperator() { - std::cout << "\n--- ArithmeticOperator Examples ---\n"; + LOG_S("\n--- ArithmeticOperator Examples ---\n"); int a{100}; int b{200}; // Addition - std::cout << "a = " << a << ", b = " << b << "\n"; + LOG_S("a = " << a << ", b = " << b); int sum = a + b; - std::cout << "sum = " << sum << "\n"; + LOG_S("sum = " << sum); // Subtraction - std::cout << "a = " << a << ", b = " << b << "\n"; - int different = a - b; - std::cout << "different = " << different << "\n"; + LOG_S("a = " << a << ", b = " << b); + uint32_t different = a - b; + LOG_S("different = " << different); // Multiplication - std::cout << "a = " << a << ", b = " << b << "\n"; + LOG_S("a = " << a << ", b = " << b); int product = a * b; - std::cout << "product = " << product << "\n"; + LOG_S("product = " << product); // Division - std::cout << "a = " << a << ", b = " << b << "\n"; + LOG_S("a = " << a << ", b = " << b); int quotient = a / b; - std::cout << "quotient = " << quotient << "\n"; + LOG_S("quotient = " << quotient); // Modulus - std::cout << "a = " << a << ", b = " << b << "\n"; + LOG_S("a = " << a << ", b = " << b); int remainder = a % b; - std::cout << "remainder = " << remainder << "\n"; + LOG_S("remainder = " << remainder); // Increment - std::cout << "a = " << a << "\n"; + LOG_S("a = " << a); int pre_in = ++a; // increase a, return a - std::cout << "preIn = " << pre_in << "\n"; + LOG_S("preIn = " << pre_in); - std::cout << "a = " << a << "\n"; + LOG_S("a = " << a); int post_in = a++; // copy a to a copy, then increase a, return copy - std::cout << "postIn = " << post_in << "\n"; + LOG_S("postIn = " << post_in); // Decrement - std::cout << "b = " << b << "\n"; + LOG_S("b = " << b); int pre_de = --b; - std::cout << "preDe = " << pre_de << "\n"; + LOG_S("preDe = " << pre_de); - std::cout << "b = " << b << "\n"; + LOG_S("b = " << b); int post_de = b--; - std::cout << "postDe = " << post_de << "\n"; + LOG_S("postDe = " << post_de); // Comma: int value = (a++, b); // a is incremented, then b is returned - std::cout << "a = " << a << ", b = " << b << "\n"; - std::cout << "comma(a++, b) = " << value << "\n"; + LOG_S("a = " << a << ", b = " << b); + LOG_S("comma(a++, b) = " << value); } -void logicalOperator() { - std::cout << "\n--- LogicalOperator Examples ---\n"; +void LOG_SicalOperator() { + LOG("\n--- LOG_SicalOperator Examples ---"); bool a = true; bool b = false; bool c = true; - std::cout << std::boolalpha; // show true/false instead of 1/0 - std::cout << "a = " << a << ", b = " << b << ", c = " << c << "\n\n"; + // show true/false instead of 1/0 + LOG_S(std::boolalpha << "a = " << a << ", b = " << b << ", c = " << c); // AND (&&) - std::cout << "[AND] a && b = " << (a && b) << "\n"; + LOG_S("[AND] a && b = " << (a && b)); // OR (||) - std::cout << "[OR ] a || b = " << (a || b) << "\n"; + LOG_S("[OR ] a || b = " << (a || b)); // NOT (!) - std::cout << "[NOT] !c = " << (!c) << "\n"; + LOG_S("[NOT] !c = " << (!c)); } void bitWiseOperator() { - std::cout << "\n--- BitWiseOperator Examples ---\n"; - std::bitset<8> bits_a {0b1111'1111}; - std::bitset<8> bits_b {0b1111'0000}; + LOG("\n--- BitWiseOperator Examples ---"); + std::bitset<8> bits_a = 0b1111'1111; std::bitset<8> bits_b = 0b1111'0000; - std::cout - << "bitA = " << bits_a << ", bitB = " << bits_b << "\n"; + LOG_S("bitA = " << bits_a << ", bitB = " << bits_b); // AND std::bitset<8> result = bits_a & bits_b; - std::cout << "bitA && bitB= " << result << "\n"; + LOG_S("bitA && bitB= " << result); // OR result = bits_a | bits_b; - std::cout << "bitA | bitB= " << result << "\n"; + LOG_S("bitA | bitB= " << result); // XOR result = bits_a ^ bits_b; - std::cout << "bitA ^ bitB= " << result << "\n"; + LOG_S("bitA ^ bitB= " << result); // NOT result = ~bits_a; - std::cout << "~bitA = " << result << "\n"; + LOG_S("~bitA = " << result); // LEFT SHIFT result = bits_a << 1; - std::cout << "bitA << 1 = " << result << "\n"; + LOG_S("bitA << 1 = " << result); // RIGHT SHIFT result = bits_a >> 1; - std::cout << "bitA >> 1 = " << result << "\n"; + LOG_S("bitA >> 1 = " << result); } \ No newline at end of file diff --git a/src/core/basics/README.md b/src/core/basics/README.md index e6c1d1c..e810be3 100644 --- a/src/core/basics/README.md +++ b/src/core/basics/README.md @@ -1,48 +1,67 @@ -# Basic C++ +--- +author: "Phong Nguyen" +title: "C++ - Chapter 2: Fundamentals" +date: "2026-05-24" +description: "C++ Notes" +tags: ["cpp"] #tags search +FAcategories: ["syntax"] #The category of the post, similar to tags but usually for broader classification. +FAseries: ["Themes Guide"] #indicates that this post is part of a series of related posts +aliases: ["migrate-from-jekyl"] #Alternative URLs or paths that can be used to access this post, useful for redirects from old posts or similar content. +ShowToc: true # Determines whether to display the Table of Contents (TOC) for the post. +TocOpen: true # Controls whether the TOC is expanded when the post is loaded. +weight: 1 # The order in which the post appears in a list of posts. Lower numbers make the post appear earlier. +--- -## 1. Initialization in C++ -C++ provides several ways to initialize objects. Each form has different semantics and use cases. +C++ Basic Concepts +- `Data` is any information processed or stored by a computer. +- A `Value` is a specific piece of data (e.g. `42`, `'A'`, `3.14`). +- An `Object` is a region of storage (memory) with a type and a value. +- A `Variable` is a named object used to store data. +- `Initialization` is the process of giving an initial value to an object or variable. +- `Literals`: fixed values like 42, 3.14, 'A', "Hello", true, nullptr. +- `Operators`: symbols that act on values (+ - * / %, == != < >, && || !, = += -=, etc.). +- An `Expression` is a combination of operators, constants and variables that evaluate to a value. +- A `function` is a reusable block of code that performs a specific task. -### 1.1 Default Initialization -Performed when an object is created **without any initializer**. +--- +## 1. Initialization +C++ provides several ways to initialize objects. Each form has different semantics and use cases. +### 1.1. Default Initialization ```cpp +int a; T object; new T; ``` -- Built-in types: uninitialized -- Class types: default constructor is called - ---- +Performed when an object is created **without any initializer**. + - **Built-in types:** uninitialized + - **Class types:** default constructor is called -### 1.2 Value Initialization -Performed when an object is created with an **empty initializer**. +
+### 1.2. Value Initialization ```cpp +int a{}; + T(); new T(); T object{}; T{}; new T{}; -``` -Also used in constructors: - -```cpp +/// @brief Also used in constructors Class::Class() : member() {} Class::Class() : member{} {} ``` -- Built-in types: zero-initialized -- Class types: default constructor is called +Performed when an object is created with an **empty initializer**. + - **Built-in types**: zero-initialized + - **Class types**: default constructor is called ---- +
### 1.3 Direct Initialization - -Initializes an object using **explicit constructor arguments**. - ```cpp T object(arg); T object(arg1, arg2); @@ -50,81 +69,384 @@ T object(arg1, arg2); T object{arg}; // since C++11 new T(args...); static_cast(other); -``` -Used in constructors and lambdas: - -```cpp +/// @brief Used in constructors and lambdas: Class::Class() : member(args...) {} [arg]() {}; ``` ---- - -### 1.4 Copy Initialization +Initializes an object using **explicit constructor arguments**. -Initializes an object **from another object or expression**. +
+### 1.4 Copy Initialization ```cpp T object = other; f(other); return other; throw object; catch (T object); + +/// @brief Also used for arrays +T array[N] = { /* values */ }; ``` +Initializes an object **from another object or expression**. -Also used for arrays: +### 1.5 List Initialization (since C++11) +```cpp +/// @brief Direct List Initialization +T object{arg1, arg2}; +new T{arg1, arg2}; + +Class::Class() : member{arg1, arg2} {} + +/// @brief Copy List Initialization +T object = {arg1, arg2}; +return {arg1, arg2}; +function({arg1, arg2}); + + +/// @brief Designated Initializers (since C++20) +T object{ .des1 = arg1, .des2 = arg2 }; +T object = { .des1 = arg1, .des2 = arg2 }; +``` +Initializes objects using **brace-enclosed initializer lists { }**. + +
+ +### 1.6 Aggregate Initialization ```cpp -T array[N] = { /* values */ }; +T object = {arg1, arg2}; +T object{arg1, arg2}; // since C++11 + +/// @brief Designated initializers for aggregates (since C++20) +T object = { .des1 = arg1, .des2 = arg2 }; +T object{ .des1 = arg1, .des2 = arg2 }; ``` +Initializes **aggregate types** (no user-defined constructors). --- +## 2. Functions and Files +### 2.1. Function +```cpp -### 1.5 List Initialization (since C++11) +returnType functionName(); ///< Forward Declaration + +/// @brief Function Definition +returnType functionName(){ + + +} +``` -Initializes objects using **brace-enclosed initializer lists**. +- A `forward declaration` allows us to tell the compiler about the existence of an identifier before actually defining the identifier. -#### Direct List Initialization +
+### 2.2. Namespace ```cpp -T object{arg1, arg2}; -new T{arg1, arg2}; +namespace nested_config{ + namespace config{ + int value = 1; + } +} -Class::Class() : member{arg1, arg2} {} +using namespace cfg = nested_config::config; + +void f(){ + std::cout << cfg::value; +} ``` +- `namespace` is a way to group names (variables, functions, classes, ...) together and avoid name conflicts. It guarantees that all identifiers within the namespace are unique +- `using namespace`: this is a using-directive that allows us to access names in the std namespace with no namespace prefix +- The `scope resolution operator (::)` used to access namespace member +- Can create `namespace aliases`, which allow us to temporarily shorten a long sequence of namespaces into something shorter. +- namespaces can be nested inside other namespaces. -#### Copy List Initialization +
+### 2.3. Preprocessor +The `preprocessor` is a process that runs on the code before it is compiled. ```cpp -T object = {arg1, arg2}; -return {arg1, arg2}; -function({arg1, arg2}); +#include // insert file contents +#define NAME "Alex" // replace NAME -> "Alex" + +#ifdef NAME_DEFINED // only compile if defined +std::cout << NAME; +#endif ``` -#### Designated Initializers (since C++20) +
+### 2.3. Header Files ```cpp -T object{ .des1 = arg1, .des2 = arg2 }; -T object = { .des1 = arg1, .des2 = arg2 }; +#include // search system only +#include "my_header.h" // search local first, then system + +/// @brief Add include directories with -I +// g++ -o main -I./source/includes -I/home/abc/moreHeaders main.cpp ``` +`Header files` are files designed to propagate declarations to code files. +- `Header guards` prevent the contents of a header from being included more than once into a given code file. +- For cross-platform library code, `#ifndef` is safest. +- For modern projects, `#pragma once` is simpler and safe. + --- +## 3. Fundamental Data Types +Memory can only store bits. `Data type` help compiler and CPU take care of encoding the value into the sequence of bits. + - Fundamental Data Types + - Compound Data Types + +### 3.1 Primitive Type +| Types | Category | Meaning | Example | +| ------------------------------------------------------------------ | -------------------- | ------------------------------------------------ | ------- | +| float, double, long double | Floating Point | a number with a fractional part | 3.14159 | +| bool | Integral (Boolean) | true or false | true | +| char, wchar_t, char8_t (C++20), char16_t (C++11), char32_t (C++11) | Integral (Character) | a single character of text | 'c' | +| short int, int, long int, long long int (C++11) | Integral (Integer) | positive and negative whole numbers, including 0 | 64 | +| std::nullptr_t (C++11) | Null Pointer | a null pointer | nullptr | +| void | Void | no type | n/a | + +- `sizeof` used to get the size of a type in bytes. (pointer has 4 or 8 bytes based on the arch) +- `signed integers` can hold both positive and negative numbers (and 0). +- `unsigned integers` can only hold non-negative whole numbers. +- `fixed-width integers` are the set of integer types that are guaranteed to be the same size on any architecture **`#include `** + - `fast integers`: guarantee at least # bits, but pick the type that the CPU can process fastest (even if it uses more memory). + - `least integers`: guarantee at least # bits, but pick the type that uses the least memory (even if it’s slower). +- `size_t` vs `std::size_t` is an unsigned integral type that is used to represent the size or length of objects. (, ) +- `scientific notation e/E` used to present the times 10 to the power of the equation. e.g. **(e.g. 5.9722 x 10²⁴ -> 5.9722e24)** +- `Inf` represents infinity. Inf is signed, and can be positive (+Inf) or negative (-Inf). (5/0) +- `NaN` stands for “Not a Number”. (mathematically invalid) + +
+ +### 3.2. Chars +- A `char` variable are interpreted as an `ASCII character`. +- `'t'`: Text between single quotes is treated as a char literal, which represents a single character. +- `"text"`: Text between double quotes (e.g. “Hello, world!”) is treated as a C-style string literal, which can contain multiple characters. +- **Escape sequences:** + | Name | Symbol | Meaning | + | --------------- | ------------ | ---------------------------------------------- | + | Alert | `\a` | Makes an alert, such as a beep | + | Backspace | `\b` | Moves the cursor back one space | + | Formfeed | `\f` | Moves the cursor to next logical page | + | Newline | `\n` | Moves cursor to next line | + | Carriage return | `\r` | Moves cursor to beginning of line | + | Horizontal tab | `\t` | Prints a horizontal tab | + | Vertical tab | `\v` | Prints a vertical tab | + | Single quote | `\'` | Prints a single quote | + | Double quote | `\"` | Prints a double quote | + | Backslash | `\\` | Prints a backslash | + | Question mark | `\?` | Prints a question mark *(no longer relevant)* | + | Octal number | `\{number}` | Translates into char represented by octal | + | Hex number | `\x{number}` | Translates into char represented by hex number | -### 1.6 Aggregate Initialization +--- +## 4. Constant +- A `constant` is a value that is not be changed during the program’s execution. There are two types of constants: + - **Named constants**: are constant values that are associated with an identifier. + - Constant variables + - Macros with substitution text + - Enumerated constant + - **Literal** are constant values that are not associated with an identifier.Literals are values that are inserted directly into the code. -Initializes **aggregate types** (no user-defined constructors). +
+### 4.1. Named constants ```cpp -T object = {arg1, arg2}; -T object{arg1, arg2}; // since C++11 +const double gravity = 9.8; ///< Const variable + +#define MY_NAME "Phong" ///< Object-like macros with substitution text + +enum Color { + RED, // Assigned 0 + GREEN, // Assigned 1 + BLUE = 5, // Manually assigned 5 + YELLOW // Assigned 6 (5 + 1) +};///< Enumerated constant ``` -Designated initializers for aggregates (since C++20): +### 4.2. Literals ```cpp -T object = { .des1 = arg1, .des2 = arg2 }; -T object{ .des1 = arg1, .des2 = arg2 }; +return 5; ///< 5 is an integer literal -> type: int +bool myNameIsAlex { true }; ///< true is a boolean literal -> type: bool +double d { 3.4 }; ///< 3.4 is a double literal -> type: double +cout << "Hello, world!"; ///< "Hello, world!" is a C-style string literal -> type: const char[14] +cout << 5.0 << '\n'; ///< 5.0 (no suffix) is type double (by default) +cout << 5.0f << '\n'; ///< 5.0f is type float +``` + +- `Type of a literal` is deduced from the literal's value. +- `Literal suffixes` used to explicitly declare the type for a literal. + +
+ +### 4.3. Numeral systems (decimal, binary, hexadecimal, and octal) +- Numeral system literals: + - Decimal (no prefix, 42) + - Binary (0b101010) `b` + - Hexadecimal (0x2A) `x` + - Octal (052) — all represent the same value. +- Can change the output format via use of the `std::dec, std::oct, and std::hex` I/O manipulators: +- Can define a `std::bitset` variable and tell `std::bitset` how many bits we want to store. +```cpp + int bin{}; // assume 16-bit int + bin = 0x0001; // assign binary 0000 0000 0000 0001 to the variable + bin = 0b1; // assign binary 0000 0000 0000 0001 to the variable + bin = 0b11; // assign binary 0000 0000 0000 0011 to the variable + + cout << std::bitset<4>{ 0b1010 } << '\n'; // create a temporary std::bitset and print it + + // C++14: quotation mark (‘) as a digit separator + int bin { 0b1011'0010 }; // assign binary 1011 0010 to the variable + long value { 2'132'673'462 }; // much easier to read than 2132673462 +``` + +
+ +### 4.4. Constant Expression +- `Constant expressions` is an expressions whose values can be fully determined at **compile time**. +- `constexpr` is used to declare compile-time constants +- Benefits: + - Safer code + - Optimizations + - Compile-time evaluation + +- `constexpr` function is is a function that is allowed to be called in a constant expression, can be evaluated at compile time or runtime. +- `consteval` function is a function that must evaluate at compile-time. + +```cpp +constexpr int square(int x) { + return x * x; +} + +consteval int cube(int x) { + return x * x * x; +} + +constexpr int a = square(5); // compile-time +int b = square(5); // runtime allowed + +constexpr int c = cube(5); // OK +// int d = cube(5); // Error if not compile-time +``` + +--- +## 5. Operators & Bit Manipulation +### 5.1. Operators +- Refer : https://www.learncpp.com/cpp-tutorial/operator-precedence-and-associativity/ +- `Increment/decrement`: + - `++x`: increment x, then return x + - `x++`: copy x, then increment x, return the copy +- `Comma`: + - `(x, y)`: Evaluate x then y, returns value of y + - avoid use this + +### 5.2. Bit manipulation. +- To define a set of bit flags, use `uint8/16/32`... or `std::bitset` +- Refers: https://www.learncpp.com/cpp-tutorial/bit-flags-and-bit-manipulation-via-stdbitset/ + +--- +## 6. Control Flows +### 6.1. Constexpr if statement (C++17) +- Condition will be evaluated at runtime. +- e.g. +```cpp +int main() +{ + constexpr double gravity{ 9.8 }; + + if constexpr (gravity == 9.8) // now using constexpr if + std::cout << "Gravity is normal.\n"; + else + std::cout << "We are not on Earth.\n"; + + return 0; +} ``` -- A specialized form of list-initialization \ No newline at end of file +
+ +### 6.2. Switch fallthrough and scoping +- The `[[fallthrough]]` attribute modifies a null statement to indicate that fallthrough is intentional (and no warnings should be triggered). +- Initialization is not allowed before case labels because control flow in a switch may jump over the initializer, leaving the variable uninitialized. +- Declarations without an initializer are allowed before case labels because they only reserve space for the variable in the function’s stack frame (decided at compile time). No runtime initialization code is generated, so nothing can be “skipped” by jumping to a case. +- e.g. +```cpp +int main() { + int x = 2; + + switch (x) { + int a; // allowed (no initializer, just reserves space) + // int b{5}; // not allowed (initializer may be skipped) + + case 1: + a = 10; // safe: 'a' exists, we assign here + std::cout << "Case 1, a = " << a << '\n'; + [[fallthrough]]; // intentional fallthrough to case 2 + + case 2: + a = 20; // reassign + std::cout << "Case 2, a = " << a << '\n'; + break; + + default: + std::cout << "Default case\n"; + break; + } + + return 0; +} +``` + +
+ +### 6.3. Halts +- Halts allow us to terminate our program.Only use a halt if there is no safe or reasonable way to return normally from the main function. If you haven’t disabled exceptions, prefer using exceptions for handling errors safely. +- `std::exit` is called implicitly when main() returns, it does not clean up local variables in the current function or up the call stack. +- `std::abort()` function causes your program to terminate abnormally. Abnormal termination means the program had some kind of unusual runtime error and the program couldn’t continue to run. +- `std::terminate()` function is typically used in conjunction with exceptions . By default, it calls `std::abort()` +- e.g. +```cpp +#include +#include // for std::exit, std::abort +#include // for std::terminate + +void cleanup() { + std::cout << "Cleaning up...\n"; +} + +void riskyFunction(bool fatalError) { + if (fatalError) { + std::cout << "Fatal error occurred!\n"; + + // std::abort: abnormal termination, no cleanup + std::abort(); + + // Or: std::terminate(); // usually called when exception handling fails + } +} + +int main() { + cleanup(); // local function call + + // Example 1: return normally from main + std::cout << "Program running normally...\n"; + + // Example 2: using std::exit (implicit when main returns) + if (false) { + std::cout << "Exiting via std::exit...\n"; + std::exit(0); // does not call destructors of locals in main() + } + + // Example 3: risky code that might abort/terminate + riskyFunction(true); + + // Example 4: normal end of main calls std::exit implicitly + std::cout << "Main returns normally.\n"; + return 0; // std::exit(0) is called implicitly here +} +``` \ No newline at end of file diff --git a/src/core/basics/TypeQualifier.cpp b/src/core/basics/TypeQualifier.cpp index c456f75..1044f29 100644 --- a/src/core/basics/TypeQualifier.cpp +++ b/src/core/basics/TypeQualifier.cpp @@ -1,32 +1,56 @@ // cppcheck-suppress-file [unreadVariable] -// A function declared constexpr is implicitly an inline function. -// A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable. -#include -using namespace std; +// A constexpr function is implicitly inline. +// A constexpr static data member is implicitly an inline variable (since C++17). + +#include "Logger.h" namespace { -namespace Constant { +constexpr int square(int x) { + return x * x; +} + +consteval int cube(int x) { + return x * x * x; +} + void run() { - // 1. Name constants + // 1. Named constants const double const_var_g{9.8}; + #define NAME "Phong" - // 2. Literals constants - bool myNameIsAlex{true}; // true is a boolean literal -> type: bool - double d{3.4}; // 3.4 is a double literal -> type: double - std::cout - << "Hello, world!"; // "Hello, world!" is a C-style string literal -> type: const char[14] + // 2. Literal constants + bool my_name_is_alex{true}; ///< true is a boolean literal -> type: bool + double d{3.4}; ///< 3.4 is a floating-point literal -> type: double + + // "Hello, world!" is a string literal -> type: const char[14] + LOG("Hello, world!"); - // 3. Constexpr variables - constexpr double constexpr_var_g{9.8}; // compile-time constant + // 3. constexpr variables + constexpr double kConstexprVarG{9.8}; // compile-time constant - // 4. Constant expression - constexpr double something{ - constexpr_var_g}; // ok: sum is a constant expression - // constexpr double something2{const_var_g}; // error because const_var_g is not the constexprs + // 4. Constant expressions + constexpr double kSomething{kConstexprVarG}; + + // Error: + // constexpr double something2{const_var_g}; + // const_var_g is const, but not guaranteed to be a constant expression + + if constexpr (kConstexprVarG != 9.8) { + LOG("kConstexprVarG != 9.8"); + } else { + LOG("kConstexprVarG == 9.8"); + } + + // 5. Const expression function + + constexpr int a = square(5); // compile-time + int b = square(5); // runtime allowed + + constexpr int c = cube(5); // OK + // int d = cube(5); // Error if not compile-time } -} // namespace Constant } // namespace @@ -34,10 +58,11 @@ void run() { class TypeQualifier : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/basics"; } std::string name() const override { return "TypeQualifier"; } std::string description() const override { return "TypeQualifier"; } - void execute() override { Constant::run(); } + + void execute() override { run(); } }; -REGISTER_EXAMPLE(TypeQualifier); +REGISTER_EXAMPLE(TypeQualifier); \ No newline at end of file diff --git a/src/core/class/RoleOfThreeFiveZero.cpp b/src/core/class/RoleOfThreeFiveZero.cpp index c7602c9..e055742 100644 --- a/src/core/class/RoleOfThreeFiveZero.cpp +++ b/src/core/class/RoleOfThreeFiveZero.cpp @@ -276,7 +276,7 @@ void run() { class RoleOfThreeFiveZero : public IExample { public: - std::string group() const override { return "core"; } + std::string group() const override { return "core/class"; } std::string name() const override { return "RoleOfThreeFiveZero"; } std::string description() const override { return ""; } void execute() override { From afd45c964c9e8584ab94252fa50ba95544004858 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Mon, 25 May 2026 11:05:06 +0700 Subject: [PATCH 06/18] Refactor and update readme for Strign --- src/core/basics/Operations.cpp | 2 +- src/core/string/CString.cpp | 205 +++++++------ src/core/string/README.md | 441 +++++++++++++++------------ src/core/string/StdString.cpp | 231 ++++++++------ src/core/string/StringFormatting.cpp | 63 ++-- 5 files changed, 535 insertions(+), 407 deletions(-) diff --git a/src/core/basics/Operations.cpp b/src/core/basics/Operations.cpp index b393c8d..5287455 100644 --- a/src/core/basics/Operations.cpp +++ b/src/core/basics/Operations.cpp @@ -75,7 +75,7 @@ void arithmeticOperator() { LOG_S("comma(a++, b) = " << value); } -void LOG_SicalOperator() { +void logicalOperator() { LOG("\n--- LOG_SicalOperator Examples ---"); bool a = true; bool b = false; diff --git a/src/core/string/CString.cpp b/src/core/string/CString.cpp index 3ec28cf..26ee4af 100644 --- a/src/core/string/CString.cpp +++ b/src/core/string/CString.cpp @@ -1,12 +1,14 @@ #include // C-String -#include +#include "Logger.h" namespace { +void log_string_info(const char* label, const char* str, size_t size) { + LOG_S(label << ": \"" << str << "\"" << " | size=" << size + << " | length=" << strlen(str)); +} -namespace initialize_string { - -// Memory layout (addresses are illustrative): -// Stack (modifiable array) +namespace create { +/// @brief Stack (modifiable array) // 0x7fffc000: str2[0] = 'H' // 0x7fffc001: str2[1] = 'e' // 0x7fffc002: str2[2] = 'l' @@ -15,7 +17,7 @@ namespace initialize_string { // 0x7fffc005: str2[5] = '\0' // (str2 starts at 0x7fffc000) -// Data / Read-only segment (string literal) +/// @brief String literal (Data / Read-only segment) // 0x00403000: 'H' // 0x00403001: 'e' // 0x00403002: 'l' @@ -27,165 +29,177 @@ namespace initialize_string { // Pointer variable // 0x7fffbff0: str1 = 0x00403000 // str1 holds address of string literal void run() { - // **1. As a character array (modifiable)** - 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* 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)** + LOG("=== create ==="); + + /// @brief Create a string as a character array (modifiable) + char str_array[] = "this is a string array literal"; + log_string_info("str_array", str_array, sizeof(str_array)); + str_array[0] ^= ' '; // modify first character + log_string_info("modified str_array", str_array, sizeof(str_array)); + + /// @brief Create a pointer to a string literal const (read-only) + const char* str_ptr = "this is a strPtr literal"; + log_string_info("str_ptr", str_ptr, sizeof(str_ptr)); + // str_ptr[0] ^= ' '; // ERROR + + /// @brief Create a string using sprintf / snprintf char str_formatted[50]; int num_var = 21; + const char text[] = "example"; - // sprintf (unsafe if buffer too small) - sprintf(str_formatted, "sprintf: %d", num_var); - std::cout << str_formatted << " - size " << sizeof(str_formatted) - << " - length " << strlen(str_formatted) << "\n"; + sprintf(str_formatted, "sprintf: %d", + num_var); // sprintf (unsafe if buffer too small) + log_string_info("sprintf", str_formatted, sizeof(str_formatted)); - // snprintf (safer, limits buffer size) - 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"; + snprintf(str_formatted, sizeof(str_formatted), "snprintf %s %d", text, + num_var); // snprintf (safer, limits buffer size) + log_string_info("snprintf", str_formatted, sizeof(str_formatted)); } -} // namespace initialize_string +} // namespace create -namespace copy_string { +namespace copy { void run() { + LOG("=== copy ==="); + const char src[] = "CopyStr"; char dst[50]; - // **1. Copy full string** + /// @brief Copy full string strcpy(dst, src); + log_string_info("strcpy", dst, sizeof(dst)); - std::cout << dst << " - size " << sizeof(dst) << " - length " << strlen(dst) - << "\n"; - - // **2. Copy the number of charactor** + /// @brief Copy first N characters strncpy(dst, "Hello123", 5); - dst[5] = '\0'; // ensure null-termination - - std::cout << dst << " - size " << sizeof(dst) << " - length " << strlen(dst) - << "\n"; + dst[5] = '\0'; // strncpy may not append '\0' + log_string_info("strncpy", dst, sizeof(dst)); } -} // namespace copy_string +} // namespace copy -namespace concat_string { +namespace concat { void run() { + LOG("=== concat ==="); + const char part1[] = "Hello"; const char part2[] = "World"; char dst[50] = ""; - // **1. Append full str** + /// @brief Append full strings strcat(dst, part1); strcat(dst, part2); strcat(dst, " !!"); - std::cout << dst << " - size " << sizeof(dst) << " - length " << strlen(dst) - << "\n"; + log_string_info("strcat", dst, sizeof(dst)); - // **2. Append the number of charactors** + /// @brief Append first N characters strncat(dst, "1234", 3); - std::cout << dst << " - size " << sizeof(dst) << " - length " << strlen(dst) - << "\n"; + log_string_info("strncat", dst, sizeof(dst)); } -} // namespace concat_string +} // namespace concat -namespace compare_string { +namespace compare { void run() { + LOG("=== compare ==="); + const char str1[] = "abc"; const char str2[] = "abcde"; - // **0. Compare memory** - // int memcmp ( const void * ptr1, const void * ptr2, size_t num ); + + /// @brief Compare memory + // int memcmp(const void* ptr1, const void* ptr2, size_t num); int result0 = memcmp(str1, str2, sizeof(str1)); - std::cout << "strcmp(str1, \"abcde\") = " << result0 << "\n"; + LOG_S("memcmp(str1, str2, sizeof(str1)) = " << result0); - // **1. Compare full str** + /// @brief Compare full string int result1 = strcmp(str1, "abc"); int result2 = strcmp(str1, str2); - std::cout << "strcmp(str1, \"abc\") = " << result1 << "\n"; - std::cout << "strcmp(str1, str2) = " << result2 << "\n"; + LOG_S("strcmp(str1, \"abc\") = " << result1); + LOG_S("strcmp(str1, str2) = " << result2); - // **2. Compare first N characters** + /// @brief Compare first N characters int result3 = strncmp(str1, str2, 3); - std::cout << "strncmp(str1, str2, 3) = " << result3 << "\n"; + LOG_S("strncmp(str1, str2, 3) = " << result3); } -} // namespace compare_string +} // namespace compare -namespace parse_string { +namespace parse { void run() { - char str[] = "A,B,C,D,"; // OK - // char* str = "A,B,C,D,"; // ERROR - const + LOG("=== compare ==="); - // **1. Splitting a string by some delimiter** - // 1.1. strtok - not safe - char* delimiter = ","; + char str[] = "A,B,C,D,"; + // char* str = "A,B,C,D,"; // ERROR - string literal is read-only + + const char* delimiter = ","; + + /// @brief strtok (NOT thread-safe) + LOG_S("=== strtok ==="); const char* token = strtok(str, delimiter); while (token != nullptr) { - std::cout << "strtok - token :" << token << "\n"; + LOG_S("token = " << token); + token = strtok(nullptr, delimiter); } + + /// @brief strtok problem example { - std::cout << " === problem === \n"; + LOG_S("=== strtok problem example ==="); + char str1[] = "a,b,c"; char str2[] = "1,2,3"; // Parse str1 - const char* token1 = strtok(str1, delimiter); // token1 = "a" - std::cout << "str1 first token: " << token1 << "\n"; + const char* token1 = strtok(str1, delimiter); + LOG_S("str1 first token = " << token1); // Parse str2 - const char* token2 = strtok(str2, delimiter); // token2 = "1" - std::cout << "str2 first token: " << token2 << "\n"; + const char* token2 = strtok(str2, delimiter); + LOG_S("str2 first token = " << token2); // Continue parsing str1 - token1 = strtok(nullptr, delimiter); // Unexpected! - std::cout << "str1 second token: " << token1 << "\n"; + token1 = strtok(nullptr, delimiter); + LOG_S("str1 second token = " << token1 << " (unexpected)"); } - // Have to Reset string for the next handle because strtok + /// @brief strtok_r (thread-safe / reentrant) + LOG_S("=== strtok_r ==="); + char str2[] = "one,two,three"; - // 1.2. strtok_r - safe char* saveptr; const char* token2 = strtok_r(str2, delimiter, &saveptr); + while (token2 != nullptr) { - std::cout << "strtok - token :" << token2 << "\n"; + LOG_S("token = " << token2); token2 = strtok_r(nullptr, delimiter, &saveptr); } - // **2. strcspn: find first occurrence of any chars in reject set** - const char sample[] = "hello123world"; - size_t pos = strcspn(sample, "0123456789"); // pos = 5 + /// @brief strcspn + // Find first occurrence of any character in reject set + LOG_S("=== strcspn ==="); - std::cout << "Sample string: " << sample << "\n"; - std::cout << "First digit from \"0123456789\" found at index: " << pos - << "\n"; - std::cout << "The digit is: " << sample[pos] << "\n"; + const char sample[] = "hello123world"; + size_t pos = strcspn(sample, "0123456789"); + LOG_S("sample = " << sample); + LOG_S("first digit index = " << pos); + LOG_S("digit = " << sample[pos]); } -} // namespace parse_string +} // namespace parse namespace number_conversion { void run() { - // **1. string to integer** + LOG_S("=== number_conversion ==="); + + /// @brief String to integer const char str_num[] = "100"; int num = atoi(str_num); - std::cout << num << "\n"; + LOG_S("atoi(\"100\") = " << num); - // **2. string to double** + /// @brief String to double const char str_num_d[] = "100.1234__123"; double num_d = atof(str_num_d); - std::cout << num_d << "\n"; + LOG_S("atof(\"100.1234__123\") = " << num_d); + /// @brief strtod char* end; num_d = strtod(str_num_d, &end); - std::cout << num_d << " end part:" << end << "\n"; + LOG_S("strtod = " << num_d); + LOG_S("remaining string = " << end); } } // namespace number_conversion } // namespace @@ -198,12 +212,11 @@ class CString : public IExample { std::string name() const override { return "C-String"; } std::string description() const override { return "C-String Example"; } void execute() override { - initialize_string::run(); - copy_string::run(); - concat_string::run(); - compare_string::run(); - parse_string::run(); - + create::run(); + copy::run(); + concat::run(); + compare::run(); + parse::run(); number_conversion::run(); } }; diff --git a/src/core/string/README.md b/src/core/string/README.md index 45dc79a..3e6afef 100644 --- a/src/core/string/README.md +++ b/src/core/string/README.md @@ -1,27 +1,195 @@ -# 1. String Formatting +# String + +## 1. C-Style String +A C-Style string is any **null-terminated byte string**, where this is a sequence of nonzero bytes followed by a byte with zero (0) value (the terminating null character). +- The terminating null character is represented as the character literal **'\0'**; +- The length of an NTBS is the number of elements that precede the terminating null character. An empty NTBS has a length of zero. +- The size of an NTBS is the size of the entire array, including the terminating null character. +- A single quotes `(')` are used to identify **character literals**. +- A double quotes `('')` are used to identify **string literals**. String literals are stored in your program image, usually in a read-only section (.data), + +
+ +### 1.1. Create a String +```c +// *1. Ptr +char* strMessagePtr= "abc"; +// sizeof(strMessage) = 32 or 64 (ptr) +strMessagePtr[0] = 1; // error, ptr to const + +// *2. Arrays +char strMessage[] = "abc"; +// sizeof(strMessage ) = 4 +strMessage[1] = 'a'; // OK +``` +- For `strMessage`, the memory for the array is allocated on the stack at runtime. The compiler initializes it from the string literal. At runtime, the program memory copies the string literal into the array +- For `strMessagePtr`, only the address of the string literal is held on the stack, and there is no copying of string literal. + +
+ +### 1.2. Characters +- Null: `\0`, `0x00`, `NULL` +- Carriage Return And New Line: `\r\n` +- Case switching: `'A' ^ ' '` & `'a' ^ ' '` +- Special: `\\`, +- **Escape sequences:** + | Name | Symbol | Meaning | + | --------------- | ------------ | ---------------------------------------------- | + | Alert | `\a` | Makes an alert, such as a beep | + | Backspace | `\b` | Moves the cursor back one space | + | Formfeed | `\f` | Moves the cursor to next logical page | + | Newline | `\n` | Moves cursor to next line | + | Carriage return | `\r` | Moves cursor to beginning of line | + | Horizontal tab | `\t` | Prints a horizontal tab | + | Vertical tab | `\v` | Prints a vertical tab | + | Single quote | `\'` | Prints a single quote | + | Double quote | `\"` | Prints a double quote | + | Backslash | `\\` | Prints a backslash | + | Question mark | `\?` | Prints a question mark *(no longer relevant)* | + | Octal number | `\{number}` | Translates into char represented by octal | + | Hex number | `\x{number}` | Translates into char represented by hex number | + +
+ +### 1.3. C String Libraries +- Copying strings : `strcpy`, `strncpy` +- Concatenating strings: `strcat`, `strncat` +- Comparing strings: `strcmp`, `strncmp` +- Parsing strings: `strtok`, `strcspn` +- Length: `strlen` +- Examples: +```cpp +#include +#include + +int main() { + // ------------------------------- + // 1. Copying strings + // ------------------------------- + char src[] = "Hello"; + char dst[20]; + + strcpy(dst, src); // copy full string + // dst = "Hello" + + strncpy(dst, "World", 3); // copy only 3 chars + dst[3] = '\0'; // ensure null-termination + // dst = "Wor" + + // ------------------------------- + // 2. Concatenating strings + // ------------------------------- + char text[20] = "Hi"; + strcat(text, " there"); // append full string + // text = "Hi there" + + strncat(text, "!!!", 2); // append only 2 chars + // text = "Hi there!!" + + // ------------------------------- + // 3. Comparing strings + // ------------------------------- + int r1 = strcmp("abc", "abc"); // r1 = 0 (equal) + int r2 = strcmp("abc", "abd"); // r2 < 0 (abc < abd) + int r3 = strncmp("abcdef", "abcxyz", 3); // r3 = 0 (first 3 chars equal) + + // ------------------------------- + // 4. Parsing strings + // ------------------------------- + char line[] = "A,B,C"; + char* token = strtok(line, ","); // first token: "A" + while (token != NULL) { + printf("token: %s\n", token); + token = strtok(NULL, ","); + } + + // strcspn: find first occurrence of any chars in reject set + char sample[] = "hello123world"; + size_t pos = strcspn(sample, "0123456789"); + // pos = 5 (first digit is at index 5) + + // ------------------------------- + // 5. Length + // ------------------------------- + size_t len = strlen("abc"); // len = 3 + + return 0; +} +``` -| Method | Standard | Pros | Cons | -|------------------|----------|--------------------------|------------------------------| -| `std::format` | C++20 | Clean, safe, Python-like | Needs newer compiler | -| `+` concatenation | C++98 | Simple | Hard to format numbers | -| `stringstream` | C++98 | Flexible streaming | Slow, verbose | -| `snprintf` | C | Very fast, classic | Unsafe if misused | -https://www.geeksforgeeks.org/cpp/strings-in-cpp/ -https://hackingcpp.com/cpp/std/string_basics +
+ +### 1.4. String/Numbers Conversion +- Integer to String: `itoa()` (non-standard) +- String to Double: `atof()` +- String to Double (with error checking): `strtod()` +- String to Long (with base + error checking): `strtol()` +- e.g. +```c +#include +#include // atof, strtod, strtol +#include // itoa (non-standard on some compilers) + +int main() { + // ------------------------------- + // 1. Integer → String (itoa) + // ------------------------------- + char buf[32]; + itoa(1234, buf, 10); // convert integer to string in base 10 + // buf = "1234" + + itoa(255, buf, 16); // convert to hex + // buf = "ff" + + // ------------------------------- + // 2. String → Double (atof) + // ------------------------------- + double d1 = atof("3.14159"); + // d1 = 3.14159 + + double d2 = atof("12.5xyz"); + // d2 = 12.5 (atof stops at non-numeric chars) + + // ------------------------------- + // 3. String → Double (strtod) + // ------------------------------- + char* end; + double d3 = strtod("45.67abc", &end); + // d3 = 45.67 + // end -> "abc" + + // ------------------------------- + // 4. String → Long (strtol) + // ------------------------------- + long v1 = strtol("1234", NULL, 10); + // v1 = 1234 (decimal) + + long v2 = strtol("FF", NULL, 16); + // v2 = 255 (hex → decimal) + + char* end2; + long v3 = strtol("100xyz", &end2, 10); + // v3 = 100 + // end2 -> "xyz" + + return 0; +} +``` ---- +
-# 2. Create Strings +--- +## 2. C++ String **** +Strings are objects that represent sequences of characters. +### 2.1. Create a String ```cpp -std::string s = "hello"; -std::string s2("hello"); -std::string s3(5, 'a'); // "aaaaa" +std::string s = "hello"; ///< initialize from a string literal +std::string s2("hello"); ///< direct initialization from a string literal +std::string s3(5, 'a'); ///< create a string with 5 copies of 'a' -> "aaaaa" ``` ---- - -# 3. Basic Properties +### 2.2. Basic Properties | Function | Description | | ------------ | --------------------- | | `s.size()` | number of characters | @@ -29,191 +197,89 @@ std::string s3(5, 'a'); // "aaaaa" | `s.empty()` | check empty | | `s.clear()` | remove all characters | ---- - -# 4. Access Characters - +### 2.3. Access Characters ```cpp s[0] // no bounds check s.at(0) // bounds check s.front() // first char s.back() // last char ``` - ---- - -# 5. Modify String - -## append - +### 2.4. Modify String ```cpp +/// @brief append s.append(" world"); s += " world"; -``` - -## insert -```cpp +/// @brief insert s.insert(5, "XXX"); -``` -## erase - -```cpp +/// @brief erase s.erase(0,2); -``` - -## replace -```cpp +/// @brief replace s.replace(0,5,"hi"); -``` - -## remove `\n` - -```cpp - std::string s = "hello\nworld\n"; - auto new_end = std::remove(s.begin(), s.end(), '\n'); - s.erase(new_end) - // std::erase(s,'\n') - s.erase(std::remove(s.begin(), s.end(), '\n'), s.end()); -``` - - ---- -# 6. Substring - -```cpp -std::string sub = s.substr(pos, len); +/// @brief remove `\n` +std::string s = "hello\nworld\n"; +auto new_end = std::remove(s.begin(), s.end(), '\n'); +s.erase(new_end) +// std::erase(s,'\n') +s.erase(std::remove(s.begin(), s.end(), '\n'), s.end()); ``` - -Example: - +### 2.5. Substring ```cpp +/// @brief std::string sub = s.substr(pos, len); , substr() does NOT modify original string std::string s = "abcdef"; - s.substr(2,3); // "cde" ``` +### 2.6. Find / Search +```cpp +/// @brief find character +s.find('a'); -Important: - -``` -substr() does NOT modify original string -``` - ---- -# 7. Find / Search +/// @brief find last +s.find('a'); -## find substring -```cpp +/// @brief find substring size_t pos = s.find("abc"); - if (pos != std::string::npos) std::cout << "found"; ``` - -## find char - -```cpp -s.find('a'); -``` - -## find last - -```cpp -s.rfind("abc"); -``` - ---- - -# 8. Compare Strings - +### 2.6. Compare Strings ```cpp if (a == b) if (a != b) if (a < b) -``` - -Using compare: -```cpp -a.compare(b) -``` - -Return: - -``` -0 -> equal -<0 -> smaller ->0 -> larger +// 0 -> equal +// <0 -> smaller +// >0 -> larger +auto ret = a.compare(b); ``` - -### C++20 - +### 2.7. Start/End Checking ```cpp +/// @brief C++20 s.starts_with("abc"); s.ends_with("xyz"); -``` - -### Before C++20 -#### starts_with - -```cpp +/// @brief before c++ 20 s.rfind("abc",0) == 0 -``` - -#### ends_with - -```cpp s.size() >= 3 && s.compare(s.size()-3,3,"xyz") == 0 ``` - ---- - -# 9. Convert String - -## string → int - -### C++11 - +### 2.8. Convert String ```cpp +/// @brief string to int int n = std::stoi(s); -``` - -Other: - -``` -stol -stoll -stof -stod -``` - -Example: - -```cpp double x = std::stod("3.14"); -``` - ---- - -## number → string -```cpp +/// @brief int to string std::string s = std::to_string(123); ``` ---- - -# 10. String Parsing - -## split using stringstream - +### 2.9. String Parsing ```cpp #include @@ -226,31 +292,13 @@ while(std::getline(ss,item,',')) { } ``` -Result - -``` -a -b -c -``` - ---- - -# 11. Trim Whitespace (manual) - -Common pattern: - +### 2.10. Trim Whitespace ```cpp s.erase(0, s.find_first_not_of(" \t\n\r")); s.erase(s.find_last_not_of(" \t\n\r") + 1); ``` -Removes leading/trailing spaces. - ---- - -# 12. Convert Case - +### 2.11. Convert Case ```cpp #include @@ -258,38 +306,27 @@ std::transform(s.begin(), s.end(), s.begin(), ::tolower); std::transform(s.begin(), s.end(), s.begin(), ::toupper); ``` ---- - -# 20. Functions Modify the String - -Modify: - -``` -append -insert -erase -replace -clear -push_back -pop_back -``` - -Do NOT modify: +### 2.12. String Formatting -``` -substr -find -compare -size -empty -``` - -Rule: +| Method | Standard | Pros | Cons | +|------------------|----------|--------------------------|------------------------------| +| `std::format` | C++20 | Clean, safe, Python-like | Needs newer compiler | +| `+` concatenation | C++98 | Simple | Hard to format numbers | +| `stringstream` | C++98 | Flexible streaming | Slow, verbose | +| `snprintf` | C | Very fast, classic | Unsafe if misused | -``` -method() const -> does NOT modify object -``` +--- +## 3. std::cout << , std::cin >> , std::getLine(std::cin >> std::ws, std::string string) +- `std::ws` tells `std::cin` to ignore leading whitespace(tab/enter/newline(s)) before extraction. +- `std::string::length` returns length of a string that does not included the null terminator character. +- `s` suffix is a `std::string` literally, no suffix is a C-style string literally. e.g. `std::cout << "goo\n"s` +> Initializing and copy a `std::string` is slow. That's inefficient --- +## 4. std::string_view (C++17) +`std::string_view` provides read-only access to an existing string (a C-style string literal, a std::string, or a char array) without making a copy. +- A std::string_view that is viewing a string that has been destroyed is sometimes called a dangling view. When a std::string is modified, all views into that std::string are invalidated, meaning those views are now invalid. Using an invalidated view (other than to revalidate it) will produce undefined behavior. -# 21. Common Bugs \ No newline at end of file +- `sv` suffix is a `std::string_view` literally +- Modify a std::string is likely to invalidate all std::string_view that view into that. +- It may or may not be null-terminated. \ No newline at end of file diff --git a/src/core/string/StdString.cpp b/src/core/string/StdString.cpp index 4b42b66..3f7281b 100644 --- a/src/core/string/StdString.cpp +++ b/src/core/string/StdString.cpp @@ -1,159 +1,213 @@ #include +#include #include -#include +#include #include + #include "ExampleRegistry.h" +#include "Logger.h" + +namespace { + +void log_string_info(const char* label, const std::string& str) { + LOG_S(label << ": \"" << str << "\"" << " | size=" << str.size() + << " | empty=" << std::boolalpha << str.empty()); +} + +} // namespace namespace create { + void run() { - // 1. Direct initialization with literal + LOG("=== create ==="); + + /// @brief Direct initialization with literal std::string s1 = "string 1"; - // 2. Constructor initialization + /// @brief Constructor initialization std::string s2("string 2"); - // 3. Repeat character constructor + /// @brief Repeat character constructor std::string s3(5, 's'); // "sssss" - // 4. Concatenated string literals (compile-time) + /// @brief Concatenated string literals (compile-time) std::string s4 = "First " - "Second"; // -> "First Second" + "Second"; - // 5. Raw string literal (no escaping needed) + /// @brief Raw string literal (no escaping needed) std::string s5 = R"(C:\folder\file.txt)"; - // Print results - std::cout << "s1: " << s1 << '\n'; - std::cout << "s2: " << s2 << '\n'; - std::cout << "s3: " << s3 << '\n'; - std::cout << "s4: " << s4 << '\n'; - std::cout << "s5: " << s5 << '\n'; + log_string_info("s1", s1); + log_string_info("s2", s2); + log_string_info("s3", s3); + log_string_info("s4", s4); + log_string_info("s5", s5); } + } // namespace create namespace modify { + void run() { - std::string ss = "xPhong"; - std::cout << "init : " << ss << '\n'; - - // append - ss.append("Nguyen"); - std::cout << "append : " << ss << '\n'; - - // insert at position - ss.insert(6, "Vanxx"); - std::cout << "insert : " << ss << '\n'; - - // erase (pos, length) - ss.erase(9, 2); - std::cout << "erase : " << ss << '\n'; - - // erase char using pos - auto new_end = std::remove(ss.begin(), ss.end(), 'O'); - ss.erase(new_end, ss.end()); - std::cout << "erase 'O') : " << ss << '\n'; - // #include - // std::erase(ss, '\n'); - - // replace (pos, length, new_string) - ss.replace(0, 1, "My name is "); - std::cout << "replace : " << ss << '\n'; - - // convert case - std::transform(ss.begin(), ss.end(), ss.begin(), ::tolower); - std::cout << "tolower : " << ss << '\n'; - std::transform(ss.begin(), ss.end(), ss.begin(), ::toupper); - std::cout << "toupper : " << ss << '\n'; - - // trim white - ss.erase(0, ss.find_first_not_of(" \t\n\r")); - std::cout << "trim first : " << ss << '\n'; - ss.erase(ss.find_last_not_of(" \t\n\r") + 1); - std::cout << "trim last : " << ss << '\n'; + LOG("=== modify ==="); + + std::string str = "xPhong"; + log_string_info("init", str); + + /// @brief Append + str.append("Nguyen"); + log_string_info("append", str); + + /// @brief Insert at position + str.insert(6, "Vanxx"); + log_string_info("insert", str); + + /// @brief Erase by position and length + str.erase(9, 2); + log_string_info("erase", str); + + /// @brief Erase character using remove + erase idiom + auto new_end = std::remove(str.begin(), str.end(), 'O'); + str.erase(new_end, str.end()); + log_string_info("erase 'O'", str); + + // C++20 + // std::erase(str, 'O'); + + /// @brief Replace sub + str.replace(0, 1, "My name is "); + log_string_info("replace", str); + + /// @brief Convert to lowercase + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::tolower(c); }); + log_string_info("tolower", str); + + /// @brief Convert to uppercase + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::toupper(c); }); + log_string_info("toupper", str); + + /// @brief Trim leading whitespace + str = " Hello World "; + log_string_info("before trim", str); + + str.erase(0, str.find_first_not_of(" \t\n\r")); + log_string_info("trim first", str); + + /// @brief Trim trailing whitespace + str.erase(str.find_last_not_of(" \t\n\r") + 1); + log_string_info("trim last", str); } + } // namespace modify namespace sub { + void run() { - std::string ss = "PhongNguyen"; - std::cout << "init : " << ss << '\n'; - std::string first_name = ss.substr(0, 5); - std::cout << "sub : " << first_name << '\n'; + LOG("=== sub ==="); + + std::string str = "PhongNguyen"; + log_string_info("init", str); + + /// @brief Extract sub + std::string first_name = str.substr(0, 5); + log_string_info("substr", first_name); } + } // namespace sub namespace search { + void run() { - std::string ss = "PhongNguyen"; - std::cout << "init : " << ss << '\n'; + LOG("=== search ==="); + + std::string str = "PhongNguyen"; + log_string_info("init", str); - // find char - size_t pos = ss.find('N'); + /// @brief Find character + size_t pos = str.find('N'); if (pos != std::string::npos) { - std::string second_name = ss.substr(pos); // from pos to end (default) - std::cout << "find 'N' : at " << pos << " -> " << second_name << '\n'; + std::string last_name = str.substr(pos); + + LOG_S("find('N')" << " | pos=" << pos << " | result=\"" << last_name + << "\""); } - // find substring - pos = ss.find("ong"); + /// @brief Find sub + pos = str.find("ong"); if (pos != std::string::npos) { - std::cout << "find \"ong\" : at " << pos << '\n'; + LOG_S("find(\"ong\")" << " | pos=" << pos); } - // find last occurrence - pos = ss.rfind('n'); + /// @brief Find last occurrence + pos = str.rfind('n'); if (pos != std::string::npos) { - std::cout << "rfind 'n' : at " << pos << '\n'; + LOG_S("rfind('n')" << " | pos=" << pos); } } + } // namespace search namespace compare { + void run() { - std::string ss1 = "PhongNguyen"; - std::string ss2 = "PhongNguyen"; + LOG("=== compare ==="); - int result = ss1.compare(ss2); + std::string str1 = "PhongNguyen"; + std::string str2 = "PhongNguyen"; - std::cout << "compare result : " << result << '\n'; - std::cout << "equal ? : " << std::boolalpha << (result == 0) << '\n'; + /// @brief Compare strings + int result = str1.compare(str2); + LOG_S("compare result = " << result); + LOG_S("equal = " << std::boolalpha << (result == 0)); } } // namespace compare namespace convert { + void run() { - // string -> int - std::string sint = "3"; - int ivalue = std::stoi(sint); - std::cout << "stoi : " << ivalue << '\n'; + LOG("=== convert ==="); + + /// @brief String to integer + std::string str_int = "3"; + int ivalue = std::stoi(str_int); + LOG_S("stoi(\"3\") = " << ivalue); - // string -> double - std::string sdouble = "3.3"; - double dvalue = std::stod(sdouble); - std::cout << "stod : " << std::setprecision(4) << dvalue << '\n'; + /// @brief String to double + std::string str_double = "3.3"; + double dvalue = std::stod(str_double); + LOG_S("stod(\"3.3\") = " << std::setprecision(4) << dvalue); - // number -> string + /// @brief Number to string int value = 999; - std::string svalue = std::to_string(value); - std::cout << "to_string : " << svalue << '\n'; + std::string str_value = std::to_string(value); + log_string_info("to_string", str_value); } + } // namespace convert namespace parsing { + void run() { + LOG("=== parsing ==="); + std::string line = "a,b,c"; - std::cout << "init : " << line << '\n'; - char deli = ','; + log_string_info("init", line); + + /// @brief Parse CSV-like string + char delimiter = ','; std::stringstream ss(line); std::string item; - std::cout << "Parsing with delimiter ',': \n"; - while (std::getline(ss, item, deli)) { - std::cout << item << std::endl; + LOG_S("Parsing with delimiter ','"); + while (std::getline(ss, item, delimiter)) { + LOG_S("token = " << item); } } + } // namespace parsing class StdString : public IExample { @@ -161,6 +215,7 @@ class StdString : public IExample { std::string group() const override { return "core/string"; } std::string name() const override { return "StdString"; } std::string description() const override { return "StdString Example"; } + void execute() override { create::run(); modify::run(); @@ -172,4 +227,4 @@ class StdString : public IExample { } }; -REGISTER_EXAMPLE(StdString); +REGISTER_EXAMPLE(StdString); \ No newline at end of file diff --git a/src/core/string/StringFormatting.cpp b/src/core/string/StringFormatting.cpp index e8167b7..e82f132 100644 --- a/src/core/string/StringFormatting.cpp +++ b/src/core/string/StringFormatting.cpp @@ -1,70 +1,93 @@ #include #include -#include +#include #include #include #include "ExampleRegistry.h" +#include "Logger.h" + +namespace { + +void log_formatted(const char* method, const std::string& text) { + LOG_S(method << ": \"" << text << "\"" << " | size=" << text.size()); +} + +} // namespace namespace std_format { + void run() { + LOG("=== std_format ==="); + std::string name{"Phong"}; int score = 100; - std::string s = - std::format("User {} has {} points, Pi: {:.2f}\n", name, score, 3.14159); - - std::cout << s; + /// @brief C++20 std::format + std::string str = + std::format("User {} has {} points, Pi: {:.2f}", name, score, 3.14159); + log_formatted("std::format", str); } + } // namespace std_format namespace concatenation { + void run() { + LOG("=== concatenation ==="); + std::string name{"Phong"}; int score = 100; - std::string s = "User " + name + " has " + std::to_string(score) + - " points, Pi: " + std::to_string(3.14159) + "\n"; - - std::cout << s; + /// @brief String concatenation using operator+ + std::string str = "User " + name + " has " + std::to_string(score) + + " points, Pi: " + std::to_string(3.14159); + log_formatted("concatenation", str); } + } // namespace concatenation namespace stream { + void run() { + LOG("=== stream ==="); + std::string name{"Phong"}; int score = 100; + /// @brief String formatting using stringstream std::stringstream ss; - ss << "User " << name << " has " << score << " points, Pi: " << 3.14159 - << "\n"; - - std::cout << ss.str(); + ss << "User " << name << " has " << score << " points, Pi: " << std::fixed + << std::setprecision(2) << 3.14159; + log_formatted("stringstream", ss.str()); } + } // namespace stream namespace c_style { + void run() { + LOG("=== c_style ==="); + std::string name{"Phong"}; int score = 100; + /// @brief C-style formatting using snprintf char buffer[128]; - std::snprintf(buffer, sizeof(buffer), "User %s has %d points, Pi: %.2f\n", + std::snprintf(buffer, sizeof(buffer), "User %s has %d points, Pi: %.2f", name.c_str(), score, 3.14159); - - std::cout << buffer; + log_formatted("snprintf", buffer); } + } // namespace c_style class StringFormatting : public IExample { public: std::string group() const override { return "core/string"; } - std::string name() const override { return "StringFormatting"; } - std::string description() const override { - return "String formatting examples (format, concatenation, stream, " - "C-style)"; + return "String formatting examples " + "(std::format, concatenation, stringstream, C-style)"; } void execute() override { From 7d9909e857d960825491aa17d318dfcb797050cc Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 31 May 2026 14:35:25 +0700 Subject: [PATCH 07/18] update --- src/core/CMakeLists.txt | 31 +-- src/core/expression/README.md | 86 ------- .../FunctionPointer.cpp | 32 +-- src/core/function/Functional.cpp | 52 ++++ src/core/{expression => function}/Lambda.cpp | 22 +- src/core/function/README.md | 238 ++++++++++++++++++ .../AllocationOperator.cpp | 2 +- .../ArithmeticOperator.cpp | 2 +- .../AssignmentOperator.cpp | 52 ++++ .../ClassMemberAccessOperator.cpp | 2 +- .../ComparisonOperator.cpp | 2 +- .../FunctionCallOperator.cpp | 37 +++ .../operator_overloading}/InDecOperator.cpp | 32 ++- .../operator_overloading/StreamOperator.cpp} | 32 +-- .../SubscriptOperator.cpp | 2 +- .../operator_overloading}/TypeCast.cpp | 2 +- .../operator_overloading}/UnaryOperator.cpp | 2 +- src/core/overloading/AssignmentOperator.cpp | 51 ---- src/core/overloading/ParenthesisOperator.cpp | 49 ---- 19 files changed, 469 insertions(+), 259 deletions(-) delete mode 100644 src/core/expression/README.md rename src/core/{expression => function}/FunctionPointer.cpp (64%) create mode 100644 src/core/function/Functional.cpp rename src/core/{expression => function}/Lambda.cpp (74%) create mode 100644 src/core/function/README.md rename src/core/{overloading => function/operator_overloading}/AllocationOperator.cpp (96%) rename src/core/{overloading => function/operator_overloading}/ArithmeticOperator.cpp (96%) create mode 100644 src/core/function/operator_overloading/AssignmentOperator.cpp rename src/core/{overloading => function/operator_overloading}/ClassMemberAccessOperator.cpp (94%) rename src/core/{overloading => function/operator_overloading}/ComparisonOperator.cpp (95%) create mode 100644 src/core/function/operator_overloading/FunctionCallOperator.cpp rename src/core/{overloading => function/operator_overloading}/InDecOperator.cpp (71%) rename src/core/{overloading/IOOperator.cpp => function/operator_overloading/StreamOperator.cpp} (65%) rename src/core/{overloading => function/operator_overloading}/SubscriptOperator.cpp (93%) rename src/core/{overloading => function/operator_overloading}/TypeCast.cpp (94%) rename src/core/{overloading => function/operator_overloading}/UnaryOperator.cpp (91%) delete mode 100644 src/core/overloading/AssignmentOperator.cpp delete mode 100644 src/core/overloading/ParenthesisOperator.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a60525a..2cd55ad 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -67,26 +67,27 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/container/sequence/Deque.cpp ${CMAKE_CURRENT_SOURCE_DIR}/container/associative/Set.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/expression/Lambda.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/expression/FunctionPointer.cpp - # Smart pointers ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/Unique.cpp ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/Shared.cpp ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/Weak.cpp - # Operator overloading - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/ArithmeticOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/IOOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/UnaryOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/ComparisonOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/InDecOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/SubscriptOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/ParenthesisOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/TypeCast.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/AssignmentOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/ClassMemberAccessOperator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/overloading/AllocationOperator.cpp + # Function + ${CMAKE_CURRENT_SOURCE_DIR}/function/Lambda.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/FunctionPointer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/Functional.cpp + ## Operator overloading + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/ArithmeticOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/StreamOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/UnaryOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/ComparisonOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/InDecOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/SubscriptOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/FunctionCallOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/TypeCast.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/AssignmentOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/ClassMemberAccessOperator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/function/operator_overloading/AllocationOperator.cpp # Date and time ${CMAKE_CURRENT_SOURCE_DIR}/datetime/Time.cpp diff --git a/src/core/expression/README.md b/src/core/expression/README.md deleted file mode 100644 index b31d604..0000000 --- a/src/core/expression/README.md +++ /dev/null @@ -1,86 +0,0 @@ -# Theory - -## 1. Lambda Expressions -- In C++11 and later, lambda is a convenient way of defining an anonymous function object right at the location where it's involked or passed as an argument to a function. - -- Syntax: -```cpp -[=] () mutable throw() -> int -{ - int n = x + y; - return n; -} - -``` -- `[=]`: capture clause a.k.a lambda introducer -- `()`: (O) pararam list a.k.a lambda declarator -- `mutable`: (O) -- `throw()`: (O) -- `-> int`: (O) trailing-return-type -- body -- `[](){ ... }`defines a lambda -- `[](){ ... }()` defines and immediately CALLS it - -### 1.1 Capture Clause -- It uses to introduce new variables in its body, specifics which vars are captured, and whether the capture is `by value[=]` or `by reference [&]`. -- An empty capture clause `[]` indicates that the body accesses no vars in the enclosing scope. -- An identifier or `this` cannot appear more than once in a capture scope. -- Since C++14, we can introduce and initialize new vars in the capture scope. -- E.g. -```cpp -int a{}; -int b{}; - -auto f = []{ // no capture - return 1; -} - -auto f0 = [a]{ // capture by value - return a+1; -} - -auto f1 = [&a]{ - return a+=1; // capture by reference (a = 1) -} - -auto f2 = [=]{ - return a + b; // all capture by value -} - -auto f3 = [&]{ - a+=1; - b+=1; - return a + b; // all capture by reference -} - -auto f4 = [int a{}]{ // no capture - return a; -} -``` - -## 2. Function Pointers -- A function pointer is a pointer variable that stores the address of a function with a specific return type and parameter list. -- Syntax: -```cpp -// Declare -return_type (*FuncPtr) (parameter type, ....); - -// Referencing: Assigning a function’s address to the function pointer. -FuncPtr = function_name; - -// 3) Dereferencing: Invoking the function using the pointer. The dereference operator * is optional during function calls. -FuncPtr(10, 20); // Preferred -(*FuncPtr)(10, 20); // Also valid -``` - -- e.g. -```cpp -void print(int a){ - std::cout << a; -} - -void (*FuncPtr)(int a); -FuncPtr = print; -FuncPtr(1); -``` - diff --git a/src/core/expression/FunctionPointer.cpp b/src/core/function/FunctionPointer.cpp similarity index 64% rename from src/core/expression/FunctionPointer.cpp rename to src/core/function/FunctionPointer.cpp index bbc2e09..c50b6b6 100644 --- a/src/core/expression/FunctionPointer.cpp +++ b/src/core/function/FunctionPointer.cpp @@ -1,14 +1,16 @@ #include -#include #include +#include "Logger.h" namespace { int increase(int a, int b) { + LOG(""); return static_cast(a > b); } int decrease(int a, int b) { + LOG(""); return static_cast(a < b); } @@ -16,37 +18,39 @@ int decrease(int a, int b) { // // Declaring // return_type (*FuncPtr) (parameter type, ....); // 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}; +/// @brief Function Pointer +using sort_function_ptr = int (*)(int, int); +void run() { + std::vector vect{-1, -6, 4, 2, 0, 6, 3, 9, -5}; auto f_print = [](const std::vector& vec) { + std::ostringstream oss; for (const auto& e : vec) { - std::cout << e << " "; + oss << e << " "; } - std::cout << "\n"; + LOG(oss.str()); }; - std::cout << "Before sorting : \n"; + LOG("Before sorting : "); f_print(vect); - std::cout << "Sorting in descending " << "order \n"; - + LOG("Sorting in descending order"); // Use auto auto sort_type_auto = increase; std::sort(vect.begin(), vect.end(), sort_type_auto); // Use pointer - SortFcn sort_type_ptr = decrease; + sort_function_ptr sort_type_ptr = decrease; f_print(vect); - std::cout << "Sorting with absolute " << "value as parameter\n "; + LOG("Sorting with absolute value as parameter"); std::sort(vect.begin(), vect.end(), sort_type_ptr); + std::ostringstream oss; for (auto i : vect) - std::cout << i << " "; - std::cout << "\n"; + oss << i << " "; + LOG(oss.str()); } } // namespace @@ -54,7 +58,7 @@ void run() { class FunctionPointer : public IExample { public: - std::string group() const override { return "core/expression"; } + std::string group() const override { return "core/function"; } std::string name() const override { return "FunctionPointer"; } std::string description() const override { return "Function Pointer Example"; diff --git a/src/core/function/Functional.cpp b/src/core/function/Functional.cpp new file mode 100644 index 0000000..1c59db8 --- /dev/null +++ b/src/core/function/Functional.cpp @@ -0,0 +1,52 @@ +#include +#include "Logger.h" + +namespace { +// Functions for simple math operations +int add(int a, int b) { + LOG(""); + return a + b; +} +int sub(int a, int b) { + LOG(""); + return a - b; +} +int mul(int a, int b) { + LOG(""); + return a * b; +} +int divs(int a, int b) { + LOG(""); + return a / b; +} + +void func(int a, int b, const std::function& calc) { + if (!calc) { + LOG("No function provided"); + return; + } + + int result = calc(a, b); + LOG_S(result); +} + +void run() { + func(8, 2, add); + func(8, 2, sub); + func(8, 2, mul); + func(8, 2, divs); + func(8, 2, [](int a, int b) { return a % b; }); // 0 +} +} // namespace + +#include "ExampleRegistry.h" + +class Functional : public IExample { + public: + std::string group() const override { return "core/function"; } + std::string name() const override { return "Functional"; } + std::string description() const override { return "Functional Example"; } + void execute() override { run(); } +}; + +REGISTER_EXAMPLE(Functional); diff --git a/src/core/expression/Lambda.cpp b/src/core/function/Lambda.cpp similarity index 74% rename from src/core/expression/Lambda.cpp rename to src/core/function/Lambda.cpp index 47e5064..63aee7e 100644 --- a/src/core/expression/Lambda.cpp +++ b/src/core/function/Lambda.cpp @@ -5,34 +5,36 @@ // custom (2) // template void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp); -#include +#include #include +#include "Logger.h" namespace { void run() { std::vector vect{-1, -6, 4, 2, 0, 6, 3, 9, -5}; - auto f_print = [](const std::vector& vec) { + std::ostringstream oss; for (const auto& e : vec) { - std::cout << e << " "; + oss << e << " "; } - std::cout << "\n"; + LOG(oss.str()); }; - std::cout << "Before sorting : \n"; + LOG("Before sorting : "); f_print(vect); - std::cout << "Sorting in descending " << "order \n"; + LOG("Sorting in descending order"); std::sort(vect.begin(), vect.end(), [](int a, int b) { return a > b; }); f_print(vect); - std::cout << "Sorting with absolute " << "value as parameter\n "; + LOG("Sorting with absolute value as parameter"); std::sort(vect.begin(), vect.end(), [](int a, int b) { return a < b; }); + std::ostringstream oss; for (auto i : vect) - std::cout << i << " "; - std::cout << "\n"; + oss << i << " "; + LOG(oss.str()); } } // namespace @@ -40,7 +42,7 @@ void run() { class Lambda : public IExample { public: - std::string group() const override { return "core/expression"; } + std::string group() const override { return "core/function"; } std::string name() const override { return "Lambda"; } std::string description() const override { return "Lambda Expression Example"; diff --git a/src/core/function/README.md b/src/core/function/README.md new file mode 100644 index 0000000..62eaba6 --- /dev/null +++ b/src/core/function/README.md @@ -0,0 +1,238 @@ + +--- +# Functions +Functions are self-contained blocks of code designed to perform specific tasks. They promote code reusability, modularity, and abstraction. +Functions can participate in polymorphism through: +- **Compile-time polymorphism (Static Polymorphism)** + - Function overloading + - Operator overloading + - Function templates +- **Runtime polymorphism** + - Virtual functions + +--- +## 1. Function Overloading +- `function overloading` allows us to create multiple functions with the same name, so long as each identically named function has different parameter types/numbers. Return types are not considered for +- `function delete` using `delete` keyword. delete means "I forbid this", not "this doesn’t exist". +- `default-arguments`: is a default value provided for a function parameter. Parameters with default arguments must always be the rightmost parameters, and they are not used to differentiate functions when resolving overloaded functions. +```cpp +void printInt(int x) +{ + std::cout << x << '\n'; +} + +void printIntOrDefault(int x, int y = 2) +{ + std::cout << x << ", " << y << '\n'; +} + +template +void printInt(T) = delete; + +int main() +{ + printInt(97); // okay + + // printInt('a'); // compile error + // printInt(true); // compile error + + printIntOrDefault(5); // prints: 5, 2 + printIntOrDefault(5, 10); // prints: 5, 10 + + return 0; +} +``` + +--- +## 2. Operator Overloading + +- **Operator overloading** allows C++ operators to be customized for user-defined types. +- An overloaded operator is implemented as a special function called an **operator function**. + +- Operator Function Names: + ```cpp + operator op + + operator new + operator new[] + operator delete + operator delete[] + + operator co_await // C++20 + ``` + +- Operator Syntax: + | Expression | Member Function | Non-member Function | Example | + | ---------- | -------------------- | ------------------- | --------------------------------------------------- | + | `@a` | `a.operator@()` | `operator@(a)` | `!a` calls `a.operator!()` | + | `a@b` | `a.operator@(b)` | `operator@(a, b)` | `std::cout << 42` calls `std::cout.operator<<(42)` | + | `a=b` | `a.operator=(b)` | N/A | `s = "abc"` calls `s.operator=("abc")` | + | `a(b...)` | `a.operator()(b...)` | N/A | `r(1)` calls `r.operator()(1)` | + | `a[b]` | `a.operator[](b)` | N/A | `m[1]` calls `m.operator[](1)` | + | `a->` | `a.operator->()` | N/A | `p->do()` calls `p.operator->()` | + | `a@` | `a.operator@(0)` | `operator@(a, 0)` | `i++` calls `i.operator++(0)` | + +- Restrictions: + The following operators **cannot be overloaded**: + ```cpp + :: // scope resolution + . // member access + .* // member access through pointer-to-member + ?: // conditional operator + ``` + - New operators cannot be created. + - Operators such as `**`, `<>`, or `&|` are invalid. + - At least one operand must be a user-defined type. + - Overloading does not change an operator's precedence, associativity, or number of operands. + + +#### Assignment Operator (`=`) +- Return the lhs by reference +```cpp +// copy assignment +T& operator=(const T& other) +{ + // Guard self assignment + if (this == &other) + return *this; + + // + + return *this; +} + +// move assignment +T& operator=(T&& other) noexcept +{ + // Guard self assignment + if (this == &other) + return *this; // delete[]/size=0 would also be ok + + // + + return *this; +} +``` + +#### Stream Extraction and Insertion (`>>`, `<<`) +- Must be implemented as non-members cause that take a `std::istream&` or `std::ostream&` as the left hand argument `std::cout << a; std::cout.operator << (a)` +```cpp +std::ostream& operator<<(std::ostream& os, const T& obj) +{ + // write obj to stream + return os; +} + +std::istream& operator>>(std::istream& is, T& obj) +{ + // read obj from stream + if (/* T could not be constructed */) + is.setstate(std::ios::failbit); + return is; +} +``` + +#### Function Call Operator (`()`) + +#### Increment and Decrement (`++`, `--`) + +#### Binary Arithmetic Operators (`+`, `-`, `*`, `/`) + +#### Comparison Operators (`==`, `!=`, `<`, `>`, `<=`, `>=`) + +#### Array Subscript Operator (`[]`) + +#### Bitwise Operators (`&`, `|`, `^`, `~`, `<<`, `>>`) + +#### Boolean Negation Operator (`!`) + +--- +## 3. Lambda +- In C++11 and later, lambda is a convenient way of defining an anonymous function object right at the location where it's involked or passed as an argument to a function. + +- Syntax: + ```cpp + [=] () mutable throw() -> int + { + int n = x + y; + return n; + } + + ``` + - `[=]`: capture clause a.k.a lambda introducer + - `()`: *(Optional)* pararam list a.k.a lambda declarator + - `mutable`: *(Optional)* + - `throw()`: *(Optional)* + - `-> int`: *(Optional)* trailing-return-type + - `[](){ ... }` defines a lambda + - `[](){ ... }()` defines and immediately CALLS it + +### Capture Clause +- It uses to introduce new variables in its body, specifics which vars are captured, and whether the capture is `by value[=]` or `by reference [&]`. +- An empty capture clause `[]` indicates that the body accesses no vars in the enclosing scope. +- An identifier or `this` cannot appear more than once in a capture scope. +- Since C++14, we can introduce and initialize new vars in the capture scope. +- e.g. + ```cpp + int a{}; + int b{}; + + auto f = []{ // no capture + return 1; + } + + auto f0 = [a]{ // capture by value + return a+1; + } + + auto f1 = [&a]{ + return a+=1; // capture by reference (a = 1) + } + + auto f2 = [=]{ + return a + b; // all capture by value + } + + auto f3 = [&]{ + a+=1; + b+=1; + return a + b; // all capture by reference + } + + auto f4 = [int a{}]{ // no capture + return a; + } + ``` + +--- +## 4. Function Pointers +- A function pointer is a pointer variable that stores the address of a function with a specific return type and parameter list. +- Syntax: `return_type (*FuncPtr) (parameter type, ....);` +```cpp +// @brief Declaration +rtype (*FuncPtr) (atype..); + +// @brief Referencing: Assigning a function’s address to the function pointer. +FuncPtr = function_name; + +// @brief Dereferencing: Invoking the function using the pointer. The dereference operator * is optional during function calls. +FuncPtr(10, 20); // Preferred +(*FuncPtr)(10, 20); // Also valid +``` + +--- +## 5. **``** +- `std::function` is a general-purpose polymorphic function wrapper introduced in C++11. + - It can store and invoke any callable object: + - Functions + - Lambda expressions + - Functors (objects that overload `operator()`) + - Member functions (with binding) + - It provides a common interface for different callable types. + - Commonly used for callbacks, event handling, task dispatching, and functional-style programming. + - Improves code flexibility, reusability, and maintainability. + +- Syntax: `std::function name()` / `std::function< ret_t (args_t)> name = f;` / `std::function< ret_t (args_t)> name(f);` + + +--- \ No newline at end of file diff --git a/src/core/overloading/AllocationOperator.cpp b/src/core/function/operator_overloading/AllocationOperator.cpp similarity index 96% rename from src/core/overloading/AllocationOperator.cpp rename to src/core/function/operator_overloading/AllocationOperator.cpp index c599e9f..d2c44e3 100644 --- a/src/core/overloading/AllocationOperator.cpp +++ b/src/core/function/operator_overloading/AllocationOperator.cpp @@ -89,7 +89,7 @@ void run() { class AllocationOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "AllocationOperator"; } std::string description() const override { return ""; } diff --git a/src/core/overloading/ArithmeticOperator.cpp b/src/core/function/operator_overloading/ArithmeticOperator.cpp similarity index 96% rename from src/core/overloading/ArithmeticOperator.cpp rename to src/core/function/operator_overloading/ArithmeticOperator.cpp index 9997921..dd5080d 100644 --- a/src/core/overloading/ArithmeticOperator.cpp +++ b/src/core/function/operator_overloading/ArithmeticOperator.cpp @@ -72,7 +72,7 @@ void run() { class ArithmeticOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "ArithmeticOperator"; } std::string description() const override { return ""; } diff --git a/src/core/function/operator_overloading/AssignmentOperator.cpp b/src/core/function/operator_overloading/AssignmentOperator.cpp new file mode 100644 index 0000000..65f85f5 --- /dev/null +++ b/src/core/function/operator_overloading/AssignmentOperator.cpp @@ -0,0 +1,52 @@ +// cppcheck-suppress-file [unreadVariable] + +// Overloading operator= + +#include "ExampleRegistry.h" +#include "Logger.h" + +namespace { +class Cents { + public: + explicit Cents(int cents = 0) : cent_{cents} {} + + /// @brief Copy constructor + Cents(const Cents& other) { + LOG(""); + cent_ = other.cent_; + } + + /// @brief Copy assignment + Cents& operator=(const Cents& cents) { + // do the copy + LOG(""); + cent_ = cents.cent_; + return *this; + } + + private: + int cent_; +}; + +void run() { + Cents c1(100); + Cents c2; + + LOG("c2 = c1;"); + c2 = c1; // c2.operator=(c1) + + LOG("Cents c3 = c1;"); + Cents c3 = c1; // c3(c1) +} +} // namespace + +class AssignmentOperator : public IExample { + public: + std::string group() const override { return "core/overloading_operator"; } + std::string name() const override { return "Assignment Operator"; } + std::string description() const override { return ""; } + + void execute() override { run(); } +}; + +REGISTER_EXAMPLE(AssignmentOperator); \ No newline at end of file diff --git a/src/core/overloading/ClassMemberAccessOperator.cpp b/src/core/function/operator_overloading/ClassMemberAccessOperator.cpp similarity index 94% rename from src/core/overloading/ClassMemberAccessOperator.cpp rename to src/core/function/operator_overloading/ClassMemberAccessOperator.cpp index 70c7fa1..6147732 100644 --- a/src/core/overloading/ClassMemberAccessOperator.cpp +++ b/src/core/function/operator_overloading/ClassMemberAccessOperator.cpp @@ -54,7 +54,7 @@ void run() { class ClassMemberAccessOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "ClassMemberAccessOperator"; } std::string description() const override { return ""; } diff --git a/src/core/overloading/ComparisonOperator.cpp b/src/core/function/operator_overloading/ComparisonOperator.cpp similarity index 95% rename from src/core/overloading/ComparisonOperator.cpp rename to src/core/function/operator_overloading/ComparisonOperator.cpp index f69d79d..ac77598 100644 --- a/src/core/overloading/ComparisonOperator.cpp +++ b/src/core/function/operator_overloading/ComparisonOperator.cpp @@ -37,7 +37,7 @@ void run() { class ComparisonOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "ComparisonOperator"; } std::string description() const override { return ""; } diff --git a/src/core/function/operator_overloading/FunctionCallOperator.cpp b/src/core/function/operator_overloading/FunctionCallOperator.cpp new file mode 100644 index 0000000..fe3b4d0 --- /dev/null +++ b/src/core/function/operator_overloading/FunctionCallOperator.cpp @@ -0,0 +1,37 @@ +// cppcheck-suppress-file [] + +// operator() + +#include +#include "ExampleRegistry.h" +#include "Logger.h" + +namespace { +#include // for assert() + +struct Linear { + double a, b; + + double operator()(double x) const { + LOG(""); + return a * x + b; + } +}; + +void run() { + Linear f{2, 1}; // Represents function 2x + 1. + double f_0 = f(0); + LOG_S(f_0); +} +} // namespace + +class FunctionCallOperator : public IExample { + public: + std::string group() const override { return "core/overloading_operator"; } + std::string name() const override { return "FunctionCallOperator"; } + std::string description() const override { return ""; } + + void execute() override { run(); } +}; + +REGISTER_EXAMPLE(FunctionCallOperator); \ No newline at end of file diff --git a/src/core/overloading/InDecOperator.cpp b/src/core/function/operator_overloading/InDecOperator.cpp similarity index 71% rename from src/core/overloading/InDecOperator.cpp rename to src/core/function/operator_overloading/InDecOperator.cpp index f093340..f5f284e 100644 --- a/src/core/overloading/InDecOperator.cpp +++ b/src/core/function/operator_overloading/InDecOperator.cpp @@ -1,17 +1,14 @@ // cppcheck-suppress-file [postfixOperator] // prefix/posfix -#include #include "ExampleRegistry.h" +#include "Logger.h" namespace { class Cents { - private: - int m_cents_{}; - public: - explicit Cents(int cents) : m_cents_{cents} {} - int getCents() const { return m_cents_; } + explicit Cents(int cents) : cents_{cents} {} + int getCents() const { return cents_; } // pre: inc -> return new Cents& operator++(); @@ -20,25 +17,36 @@ class Cents { // return old -> inc Cents operator++(int); Cents operator--(int); + + private: + int cents_{}; }; -// pre ++x/--x +/// @brief pre ++x Cents& Cents::operator++() { - ++m_cents_; + LOG(""); + ++cents_; return *this; } + +/// @brief pre ++x Cents& Cents::operator--() { - --m_cents_; + LOG(""); + --cents_; return *this; } -// pos x++/x-- +/// @brief pos x++ Cents Cents::operator++(int) { + LOG(""); Cents temp{*this}; // create copy ++(*this); // increase origin return temp; // return old } + +/// @brief pos x-- Cents Cents::operator--(int) { + LOG(""); Cents temp{*this}; --(*this); return temp; @@ -50,13 +58,13 @@ void run() { ++cent; cent--; --cent; - std::cout << cent.getCents() << "\n"; + LOG_S(cent.getCents()); } } // namespace class InDecOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "InDecOperator"; } std::string description() const override { return ""; } diff --git a/src/core/overloading/IOOperator.cpp b/src/core/function/operator_overloading/StreamOperator.cpp similarity index 65% rename from src/core/overloading/IOOperator.cpp rename to src/core/function/operator_overloading/StreamOperator.cpp index 3ef19f2..905dd31 100644 --- a/src/core/overloading/IOOperator.cpp +++ b/src/core/function/operator_overloading/StreamOperator.cpp @@ -1,17 +1,14 @@ // cppcheck-suppress-file[] -// >> << -#include +// operator>> and operator<< #include "ExampleRegistry.h" +#include "Logger.h" namespace { class Cents { - private: - int m_cents_{}; - public: - explicit Cents(int cents) : m_cents_{cents} {} - int getCents() const { return m_cents_; } + explicit Cents(int cents) : cents_{cents} {} + int getCents() const { return 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). @@ -21,14 +18,21 @@ class Cents { // out << m_cents; // return out; // } + + private: + int cents_{}; }; +/// @brief Write obj to stream std::ostream& operator<<(std::ostream& out, const Cents& c) { + LOG(""); out << c.getCents(); return out; } +/// @brief Read obj from stream std::istream& operator>>(std::istream& in, Cents& c) { + LOG(""); int cents{}; in >> cents; c = in ? Cents{cents} : Cents{0}; @@ -38,12 +42,10 @@ std::istream& operator>>(std::istream& in, Cents& c) { void run() { Cents c1{25}; // out >> - std::cout - << c1 - << "\n"; // operator<<(std::cout, c1) -> operator<<(std::ostream,Cents) + std::cout << c1 << "\n"; // in >> - std::cin >> c1; // operator>>(std::cin,c1) -> operator<<(std::istream,Cents) + std::cin >> c1; std::cout << c1 << "\n"; // clearing lefover newline @@ -52,13 +54,13 @@ void run() { } } // namespace -class IOOperator : public IExample { +class StreamOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } - std::string name() const override { return "IOOperator"; } + std::string group() const override { return "core/overloading_operator"; } + std::string name() const override { return "StreamOperator"; } std::string description() const override { return ""; } void execute() override { run(); } }; -REGISTER_EXAMPLE(IOOperator); \ No newline at end of file +REGISTER_EXAMPLE(StreamOperator); \ No newline at end of file diff --git a/src/core/overloading/SubscriptOperator.cpp b/src/core/function/operator_overloading/SubscriptOperator.cpp similarity index 93% rename from src/core/overloading/SubscriptOperator.cpp rename to src/core/function/operator_overloading/SubscriptOperator.cpp index e2105e2..06e74a8 100644 --- a/src/core/overloading/SubscriptOperator.cpp +++ b/src/core/function/operator_overloading/SubscriptOperator.cpp @@ -34,7 +34,7 @@ void run() { class SubscriptOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "SubscriptOperator"; } std::string description() const override { return ""; } diff --git a/src/core/overloading/TypeCast.cpp b/src/core/function/operator_overloading/TypeCast.cpp similarity index 94% rename from src/core/overloading/TypeCast.cpp rename to src/core/function/operator_overloading/TypeCast.cpp index eb1d677..7ac3233 100644 --- a/src/core/overloading/TypeCast.cpp +++ b/src/core/function/operator_overloading/TypeCast.cpp @@ -51,7 +51,7 @@ void run() { class TypeCast : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "TypeCast"; } std::string description() const override { return ""; } diff --git a/src/core/overloading/UnaryOperator.cpp b/src/core/function/operator_overloading/UnaryOperator.cpp similarity index 91% rename from src/core/overloading/UnaryOperator.cpp rename to src/core/function/operator_overloading/UnaryOperator.cpp index a7322b4..020ccf4 100644 --- a/src/core/overloading/UnaryOperator.cpp +++ b/src/core/function/operator_overloading/UnaryOperator.cpp @@ -31,7 +31,7 @@ void run() { class UnaryOperator : public IExample { public: - std::string group() const override { return "core/overloading"; } + std::string group() const override { return "core/overloading_operator"; } std::string name() const override { return "UnaryOperator"; } std::string description() const override { return ""; } diff --git a/src/core/overloading/AssignmentOperator.cpp b/src/core/overloading/AssignmentOperator.cpp deleted file mode 100644 index e0c60e7..0000000 --- a/src/core/overloading/AssignmentOperator.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// cppcheck-suppress-file [unreadVariable] - -// Overloading operator= - -#include -#include "ExampleRegistry.h" - -namespace { -class Cents { - private: - int m_cents_{}; - - public: - explicit Cents(int cents = 0) : 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_; - } - - // Overload copy assignment - Cents& operator=(const Cents& cents) { - // do the copy - std::cout << "Cents& operator=(const Cents& cents)\n"; - m_cents_ = cents.m_cents_; - return *this; - } -}; - -void run() { - Cents c1{100}; - Cents c2; - c2 = c1; // calls overloaded copy assignment - Cents c3 = c1; // calls copy constructor because c3 didn't exist yet -} -} // namespace - -class AssignmentOperator : public IExample { - public: - std::string group() const override { return "core/overloading"; } - std::string name() const override { return "AssignmentOperator"; } - std::string description() const override { return ""; } - - void execute() override { run(); } -}; - -REGISTER_EXAMPLE(AssignmentOperator); \ No newline at end of file diff --git a/src/core/overloading/ParenthesisOperator.cpp b/src/core/overloading/ParenthesisOperator.cpp deleted file mode 100644 index acf133c..0000000 --- a/src/core/overloading/ParenthesisOperator.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// cppcheck-suppress-file [] - -// operator() -#include -#include "ExampleRegistry.h" - -namespace { -#include // for assert() - -class Matrix { - private: - double m_data_[4][4]{}; - - public: - double& operator()(int row, int col); - double operator()(int row, int col) const; // for const objects -}; - -double& Matrix::operator()(int row, int col) { - assert(row >= 0 && row < 4); - assert(col >= 0 && col < 4); - - 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]; -} - -void run() { - Matrix matrix; - matrix(1, 2) = 4.5; - std::cout << matrix(1, 2) << '\n'; -} -} // namespace - -class ParenthesisOperator : public IExample { - public: - std::string group() const override { return "core/overloading"; } - std::string name() const override { return "ParenthesisOperator"; } - std::string description() const override { return ""; } - - void execute() override { run(); } -}; - -REGISTER_EXAMPLE(ParenthesisOperator); \ No newline at end of file From c3adeb9b95c0bf3ab9fea438fb9f49c3328b25c2 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 6 Jun 2026 23:16:01 +0700 Subject: [PATCH 08/18] Add an example --- src/embedded/README.md | 261 ++++++++++++++++++++++++++++++++++++ src/embedded/main.c | 75 +++++++++++ src/embedded/run.sh | 61 +++++++++ src/embedded/startup.c | 78 +++++++++++ src/embedded/stm32_flash.ld | 70 ++++++++++ 5 files changed, 545 insertions(+) create mode 100644 src/embedded/README.md create mode 100644 src/embedded/main.c create mode 100755 src/embedded/run.sh create mode 100644 src/embedded/startup.c create mode 100644 src/embedded/stm32_flash.ld diff --git a/src/embedded/README.md b/src/embedded/README.md new file mode 100644 index 0000000..e8fed9a --- /dev/null +++ b/src/embedded/README.md @@ -0,0 +1,261 @@ +# Embedded Bare-Metal: Build, Link, Boot, and Debug +#### Env +```bash +$ sudo apt install gcc-arm-none-eabi +$ apt-get install qemu-system +``` + +## 1. Building Process +```bash +#Sources files #Toolchain #Object files ++-----------+ +------------------+ +-----------+ +| startup.c | ----> | | ----> | startup.o | ++-----------+ | arm-none-eabi-gcc| +-----------+ + | | ++-----------+ ----> | | ----> +-----------+ +| main.c | +------------------+ | main.o | ++-----------+ +-----------+ + | +#Linker script | ++------------------+ | +| linker_script.ld | ---------------------------------+ ++------------------+ | + v + +----------------+ + |arm-none-eabi-ld| #Linker + +----------------+ + | + v + +----------------+ + | blink.elf | #Executable + +----------------+ +``` +### 1.1. Compiler +A compiler is a software program that translates source code written in a high-level programming language into a lower-level form, such as assembly code, object code, or machine code, while preserving the program's functionality. +```bash +$ gcc # native +$ g++ +$ clang +$ arm-none-eabi-gcc # cross +$ aarch64-none-elf-gcc +``` + +### 1.2. Cross Compiler +A cross compiler is a compiler that runs on one platform (host) but generates executable code for a different platform (target). +An ARM cross compiler can run on a Linux PC and generate binaries that execute on an ARM-based embedded system. +```bash +$ arm-none-eabi-gcc +$ aarch64-none-elf-gcc +``` + +### 1.3. Toolchain +A toolchain is a collection of software development tools used to build, debug, and analyze software. +A typical embedded ARM toolchain includes: +```bash +$ arm-none-eabi-gcc # Compiler +$ arm-none-eabi-as # Assembler +$ arm-none-eabi-ld # Linker +$ arm-none-eabi-objcopy # ELF to BIN converter +$ arm-none-eabi-gdb # Debugger +``` + +`$ qemu-system-arm -M stm32vldiscovery -kernel firmware.bin` +### 1.4. Linker Script +**Linker Script** is a configuration file that tells the linker how to place the program into the mcu memory. +- Define the memory layout: Flash, RAM, Stack, Heap +- Specify available memory regions +- Place the code/data in the correct memory location +- Set the program entry point +- Optimize memory usage + +Reference: https://sourceware.org/binutils/docs/ld/Scripts.html + +#### Concept +The linker combines multiple object files into a single executable file. +Object files are stored in a special format called an `object file format` (such as ELF). Each object file contains several `sections`, and each section has a name and a size (e.g., .text, .data, .bss). +For each loadable output section, the linker defines two addresses: +- VMA (Virtual Memory Address): The address where the section will reside when the program is running. +- LMA (Load Memory Address): The address from which the section is loaded at startup. + +#### Format +- Linker scripts are text files. e.g. `stm32_flash.ld` +- Whitespace is generally ignored. +- Include comments in linker scripts just as in C + +#### Example +The simplest possible linker script has just one command: `SECTION` to describe the memory layout of the output file. + +```ld +/*stm32_flash.ld*/ +SECTIONS +{ + . = 0x10000; # the code should be loaded at address 0x10000 + .text : { *(.text)} + . = 0x8000000; # that the data should start at address 0x8000000 + .data : { *{.data}} + .bss : { *(.bss) } +} +``` +- Symbols: + - `.`: location counter + - `.text`, `.data`, and `.bss` are the sections of the output file + - `*(.text)` means all `.text` input sections in all input files. + +### 1.5. Startup Code +A microcontroller does not start executing from `main()` after power-up or reset. Instead, it begins execution at the reset vector, which points to the startup code (typically `Reset_Handler`). +- Setting initial data values in SRAM, for global variables for example. +- Zero initialization of data memory for variables that are uninitialized at load time. +- Initializing the data variables controlling heap memory, for malloc() for example. +- Performing any required system initialization. +- Calling main(). + +--- +### 2. Flashing Process +```bash + + +----------------+ + | blink.elf | #Executable + +----------------+ + | + v + +----------------+ + | OpenOCD | #Tool to download/Debug + +----------------+ + | + v + +----------------+ + | ST-LINK | #Debug probe + +----------------+ + | + v + +--------------------------------------------------+ + | STM32 FLASH | + |--------------------------------------------------| + | .isr_vector | + | .text | + | .rodata | + | Initial .data image | + +--------------------------------------------------+ + | + | RESET + v + +---------------------+ + | Reset_Handler() | + +---------------------+ + | + +----------------------+ + | Copy .data | + | Flash --> SRAM | + v + +--------------------------------------------------+ + | STM32 SRAM | + |--------------------------------------------------| + | .data | + | .bss <-- zero-filled | + | | + | Heap (optional) | + | | + | Stack (grows downward) | + +--------------------------------------------------+ + | + v + +---------+ + | main() | + +---------+ + | + v + #Application Runs# +``` + +### 2.1. Build executable +Compile the source files and link them into the `firmware.elf` +```bash +$ arm-none-eabi-gcc \ + -mcpu=cortex-m3 \ + -mthumb \ + -nostdlib \ + -ffreestanding \ + startup.c main.c \ + -T stm32_flash.ld \ + -Wl,-Map=firmware.map \ + -o build/firmware.elf +``` +- **Options:** + - `-mcpu=cortex-m3` : Generate code for the ARM Cortex-M3 processor. + - `-mthumb `: Use the Thumb instruction set. + - `-nostdlib` : Do not link the standard C runtime libraries. + - `-ffreestanding` : Compile for a freestanding environment (bare-metal system). + - `-T stm32_flash.ld` : Use the specified linker script. + - `-Wl,-Map=firmware.map` : Generate a linker map file. + - `-o build/firmware.elf` : Output executable file. +- **ELF file** does include symbol tables, debug information, or other metadata. +### 2.2. Generate a Binary Image +Convert the ELF executable into a raw binary image that contains only the program data that will be stored in Flash memory. +```bash +$ arm-none-eabi-objcopy \ + -O binary \ + build/firmware.elf \ + build/firmware.bin +``` + +### 2.3. Boot and Debug with QEMU +QEMU can emulate the `STM32VLDISCOVERY` board and load firmware +#### Start QEMU +```bash +$ qemu-system-arm \ + -M stm32vldiscovery \ + -kernel firmware.bin +``` + +### Connect with GDB +- Launch QEMU and wait for a debugger connection: + ```bash + $ qemu-system-arm \ + -M stm32vldiscovery \ + -kernel firmware.elf \ + -nographic \ + -S \ + -gdb tcp::1234 + ``` + - **Options:** + `-M stm32vldiscovery` : Emulate the STM32VLDISCOVERY board. + `-kernel firmware.elf` : Load the firmware image. + `-nographic` : Disable graphical output and use the terminal. + `-S` : Pause the CPU at reset. + `-gdb tcp::1234` : Start a GDB server on port 1234. + +- Start GDB using the ELF file so that symbol and debug information are available: + ```bash + $ arm-none-eabi-gdb firmware.elf + ``` +- Connect to the QEMU GDB server: + ```bash + target remote :1234 + ``` + +- **Useful commands:** +```bash +monitor reset # Reset the emulated target +load # Load firmware into target memory +continue # Start execution + +p counter # Inspect variables and symbols + +break main # set breakpoints +continue +``` + +### Quit QEMU +When running QEMU with `-nographic`, use: +```text +Ctrl + A, then X + +to exit the emulator. + +Other useful shortcuts: +Ctrl + A, then C Open QEMU monitor +Ctrl + A, then H Show help +Ctrl + A, then X Exit QEMU +``` + +--- \ No newline at end of file diff --git a/src/embedded/main.c b/src/embedded/main.c new file mode 100644 index 0000000..e353ce8 --- /dev/null +++ b/src/embedded/main.c @@ -0,0 +1,75 @@ +#include + +#define SYST_CSR (*(volatile uint32_t*)0xE000E010) +#define SYST_RVR (*(volatile uint32_t*)0xE000E014) +#define SYST_CVR (*(volatile uint32_t*)0xE000E018) + +#define RCC_APB2ENR (*(volatile uint32_t*)0x40021018) + +#define USART1_SR (*(volatile uint32_t*)0x40013800) +#define USART1_DR (*(volatile uint32_t*)0x40013804) +#define USART1_BRR (*(volatile uint32_t*)0x40013808) +#define USART1_CR1 (*(volatile uint32_t*)0x4001380C) + +/// @brief Generate a blocking delay using the Cortex-M SysTick timer. +/// @param ms Delay duration in milliseconds. +static void delay_ms(uint32_t ms) { + while (ms--) { + SYST_RVR = 8000 - 1; // 8 MHz -> 1 ms + SYST_CVR = 0; + SYST_CSR = 5; // ENABLE + CPU clock + + while (!(SYST_CSR & (1 << 16))) {} + + SYST_CSR = 0; + } +} + +/// @brief Send a null-terminated string to the host using semihosting. +/// @param s String to transmit. +static void semihost_write0(const char* s) { + register int op asm("r0") = 0x04; + register const char* msg asm("r1") = s; + + asm volatile("bkpt 0xAB" : : "r"(op), "r"(msg) : "memory"); +} + +static void uart_init(void) { + // Enable USART1 clock + RCC_APB2ENR |= (1 << 14); + + // 8 MHz PCLK -> 115200 baud + USART1_BRR = 0x45; + + // UE + TE + USART1_CR1 = (1 << 13) | (1 << 3); +} + +/// @brief +static void uart_putc(char c) { + while (!(USART1_SR & (1 << 7))) {} + + USART1_DR = c; +} + +/// @brief Transmit a null-terminated string over USART1. +/// @param s String to transmit. +static void uart_puts(const char* s) { + while (*s) { + if (*s == '\n') + uart_putc('\r'); + + uart_putc(*s++); + } +} + +int main(void) { + uart_init(); + + while (1) { + uart_puts("Hello STM32-QEMU UART1\n"); + delay_ms(1000); + semihost_write0("Hello STM32-QEMU semihosting\n"); + delay_ms(1000); + } +} \ No newline at end of file diff --git a/src/embedded/run.sh b/src/embedded/run.sh new file mode 100755 index 0000000..afc89d2 --- /dev/null +++ b/src/embedded/run.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +set -e + +BUILD_DIR=build +TARGET=firmware + +mkdir -p ${BUILD_DIR} + +echo "[1/3] Building ELF..." + +arm-none-eabi-gcc \ + -mcpu=cortex-m3 \ + -mthumb \ + -nostdlib \ + -ffreestanding \ + startup.c main.c \ + -T stm32_flash.ld \ + -Wl,-Map=${BUILD_DIR}/${TARGET}.map \ + -o ${BUILD_DIR}/${TARGET}.elf + +echo "[2/3] Generating BIN..." + +arm-none-eabi-objcopy \ + -O binary \ + ${BUILD_DIR}/${TARGET}.elf \ + ${BUILD_DIR}/${TARGET}.bin + +QEMU_ARGS=" + -M stm32vldiscovery + -kernel ${BUILD_DIR}/${TARGET}.elf + -semihosting-config enable=on,target=native +" + +case "$1" in + gui) + echo "[3/3] Starting QEMU (GUI)..." + + qemu-system-arm ${QEMU_ARGS} + ;; + + debug) + echo "[3/3] Starting QEMU (Debug Mode)..." + echo "Connect with:" + echo " arm-none-eabi-gdb ${BUILD_DIR}/${TARGET}.elf" + echo " target remote :1234" + + qemu-system-arm \ + ${QEMU_ARGS} \ + -S \ + -gdb tcp::1234 + ;; + + *) + echo "[3/3] Starting QEMU (Terminal)..." + + qemu-system-arm \ + ${QEMU_ARGS} \ + -nographic + ;; +esac diff --git a/src/embedded/startup.c b/src/embedded/startup.c new file mode 100644 index 0000000..9fbfb2f --- /dev/null +++ b/src/embedded/startup.c @@ -0,0 +1,78 @@ +#include + +/// @brief Symbols defined by the linker script. +extern uint32_t _sidata; ///< Start address of initialized data in Flash (LMA) +extern uint32_t _sdata; ///< Start address of .data section in RAM (VMA) +extern uint32_t _edata; ///< End address of .data section in RAM +extern uint32_t _sbss; ///< Start address of .bss section +extern uint32_t _ebss; ///< End address of .bss section +extern uint32_t _estack; ///< Initial stack pointer (top of RAM) + +extern int main(void); + +void Reset_Handler(void); +void Default_Handler(void); + +/// @brief Weak aliases allow users to override handlers bydefining their own implementation with the same name. +void NMI_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void UsageFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void SVC_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler"))); + +/// @brief Interrupt Vector Table +__attribute__((section(".isr_vector"))) const void* vector_table[] = { + &_estack, // Initial SP + Reset_Handler, + + NMI_Handler, + HardFault_Handler, + MemManage_Handler, + BusFault_Handler, + UsageFault_Handler, + + 0, + 0, + 0, + 0, + + SVC_Handler, + DebugMon_Handler, + 0, + PendSV_Handler, + SysTick_Handler, +}; + +/// @brief Executed immediately after reset. +/// Responsible for initializing the C runtime environment +void Reset_Handler(void) { + // Copy initialized data (.data) * from Flash to RAM. + uint32_t* src = &_sidata; + uint32_t* dst = &_sdata; + + while (dst < &_edata) { + *dst++ = *src++; + } + + dst = &_sbss; + + // Clear uninitialized data (.bss) + while (dst < &_ebss) { + *dst++ = 0; + } + + // Jump to the application entry point + main(); + + // main() should never return + while (1) {} +} + +/// @brief Default handler for unimplemented exceptions. +void Default_Handler(void) { + while (1) {} +} \ No newline at end of file diff --git a/src/embedded/stm32_flash.ld b/src/embedded/stm32_flash.ld new file mode 100644 index 0000000..3c7c2af --- /dev/null +++ b/src/embedded/stm32_flash.ld @@ -0,0 +1,70 @@ +/* Reference: +* https://kleinembedded.com/stm32-without-cubeide-part-1-the-bare-necessities +FLASH (0x08000000) ++------------------+ +| .isr_vector | ++------------------+ +| .text | +| .rodata | ++------------------+ +| Initial .data | <-- _sidata (LMA) ++------------------+ + +RAM (0x20000000) ++------------------+ +| .data | <-- _sdata ++------------------+ +| .bss | <-- _sbss ++------------------+ +| Heap (optional) | <-- end +| | ++------------------+ +| Stack | ++------------------+ +| _estack | ++------------------+ +*/ + +ENTRY(Reset_Handler) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 8K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + } > FLASH + + _sidata = LOADADDR(.data); + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM + + . = ALIGN(8); + end = .; +} \ No newline at end of file From 7c1de38d7b619bf502b4f2c44f444d5511784145 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 14 Jun 2026 15:27:51 +0700 Subject: [PATCH 09/18] remove docs --- docs/image/future_promis.png | Bin 121085 -> 0 bytes docs/image/future_promis_flow.png | Bin 36392 -> 0 bytes src/core/basics/README.md | 452 ------------------------------ src/core/concurrency/README.md | 237 ---------------- src/core/exception/README.md | 14 - src/core/function/README.md | 238 ---------------- src/core/smart_pointer/README.md | 164 ----------- src/core/string/README.md | 332 ---------------------- 8 files changed, 1437 deletions(-) delete mode 100644 docs/image/future_promis.png delete mode 100644 docs/image/future_promis_flow.png delete mode 100644 src/core/basics/README.md delete mode 100644 src/core/concurrency/README.md delete mode 100644 src/core/exception/README.md delete mode 100644 src/core/function/README.md delete mode 100644 src/core/smart_pointer/README.md delete mode 100644 src/core/string/README.md diff --git a/docs/image/future_promis.png b/docs/image/future_promis.png deleted file mode 100644 index 73da3f7816f8e4bf289d61c1980c3ad97f473335..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121085 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 Xe0kw$kAi0~&_88)4Y@iQ^H2W|)mhrv diff --git a/docs/image/future_promis_flow.png b/docs/image/future_promis_flow.png deleted file mode 100644 index 1942fba927f86678d1c6eba54d9e05103093cf72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36392 zcmeFZ1yq%5+b&8;$fP9&DFG3bM!Hjw6htYJ6p#k#20>a71Z0wu5=tX!PzsY)>6Dg` z&U2${{ont6-yZvn|D1jH-s6nT7;Cs>I^THS=Xvg{?l)XRO_AU{&3QC5Gy-KMIW06a z3=;Uy85aY7Bhfr`0S%1-O<7L*wmbStgP-1Q^OI9Q6fG6k{jKS?ia-~3bEBs(DD9qp ztD*{j_tn}uCG}da%IeK`!*%wu*@8EErA+0IlrtZsVyCdYN_>=JFR7H1RdC<>gyA9y zIe9God0vFGpUGPF?yk#^FAf$jgy)gMTqixwKWkCPo?|id;-zes7B4QE?4e^wq2Z#T zGcZJp!}3QXZl0tr!-YT5Fr=ieqOT(gax&=8{(^?$RN_4QMe)n!No7x8*ryBi(zP`RT`cv}V ziS(8roQqKkixsbCS$+5uy(D%=oy`P>1_qQ+{VBzHrPhniN#$(rtthKIy1LO9ZxAw8 zIM0`)i{E#hE@UznDB~qSo~$f2(()=z^z}{8&np%(?(hB_d#AOPh)hlB{kAp}Y#H`; zdrPM)S8I}5vfq5LP-nK|wIJ$So$Cnw>7n-ByZd}hmz?^1P_fbnZ{PC1t$Sc<8bd3* zd3rK&8n1N6(~cC!tUi?t$=FFD_JK|&$nq$%aEr}yH(~&V@j-bP*TtBSI_Gp}#6H}T z^Ik=J=Hg9MSEfnw>dM)P&!HTid|cX$+}YWwwE0R%Cz3ED6s)14(KFi-ubw6%-~Q~* ztM>AgBNgM(CeQ7qFUfq{o(;N1Q86)G92{g93KA13oH}Y8XY$puqWbgH6>-mDVcpiz z>3YG#%)sD3Q`4KRNH6Z0U?k)?Ef=hzr}r%Y6X%lmx^$ERpVO?;ftATr-p0lTIy(Bj zVz-_Q>BYsx$3I6iV_I8VnS$XyKY#w*7Iks{a3VdNjO}ErU;X*>=Wv?cU%!5BY$z)! z?M*$QU(gvsT|a!?9&*EObnmnA2`MRQR^oBh_)Hl^TH^ zr7*L$cDgsyG+edHJnY>4QW%#pO2PSXXSLROUShqOi=U<|LprF+c0YEfh3YXoP7|MS zl_VW?4qM&&ov%mxzj#{xj%MhUnNJ%C($t<1KYjZ2J=I8O@n?LVRyT@gvcuvhd!@uO z4PLvs_d9qMaLFkt<6FhO8ZVQ5uW@8vweTw*zNtP*ZQ1>DV|$wgUv}%q7YhAlom-^k z@z4ADUTN5-x6!(up?j>+=3uK*Vs66|=`% zM_M*2?V`cHJbI7oi!LIYx217eSXkmJg=~g6eOYIPczK^S>MJ27#l3b0tSgU@J_lQi zgGH1c({Vc)85yCW*u1Z|%RftSL~g+2hcVk@RJvR1xm{SC*98+_fF^2^G?=&&YnmE2 z^W^yOm$p2v&;FcWdzsd3nOgISi|wE}`x`l(D!U4uuXUWqRZh#BGE3A$_#K+7C)=fd zB!k`QlIq|322+tpwR=~lmcN$9Ctm+rSnS%p8<~=lvcB#>ns&N;&iH}8ZSft~HZIzo zawogoBeVJwJ$a<2@r0D_xHC%JlAp%L+FJ0@u-v_qo$4l&NSGF<2Va|>C9(e>-JziHy-CS)JbK&4X8FVE@jgro8OkUt=Hqk4cS?Dz?47hkir z|0{Lk=*Q0LNM&UuCN_e>Com`o^-|cBH+jK%b4Fc)@eUr+(D3bhD#>48_{_e2ilFp6 zT&?ENea(=Ek~rjKVGv@dU394{)~|k^m}p^X8Lu)uGo!4&L~UYXGJ9gbI$W7U)DRHQ z^n}4KsXtEoV6Ex&q+xfQ+1X>`6Q#<{o9$8ZNv|e!?F@~qEE$Ch$A~14qwBd#dx0?_Hde|?a;rxcH`DlJGimmA=RFprNkjMILA~$s0hzj(^n>GN<5SZ1o9d6= zkiWK$bWFM{%%hzWdXw<>EOio>F>3^upx{n(0A_Jz&^QThSV%~e)rv;66V>_>4Ki**lY zrN9@#L20q`KYwuTu@*Ca;Mg9m8RqJ z_3P1s4k7RrxHt<#40uL=#^Jz?UC=D+{2Fmm>XI zxFFI7kA}gNDR|uP)W-&SM4?#~sB?{nLwy`17@^hB$YHJlW>o9WxDSU zb??aV?|ZIeVP)O?8ayfPa3Z@Cv*^?Moa2raiY_GN^7;Kw=@LnMYXsh>$GbTwxUa)G+h87p265PEW+%%$JpMN51KIDr0D{GR#J9^s7s18qD(1%!)f` zO3qAJeyi1Rff+z&$T#8ri$K%t_+VQ$6d{dkZfU8W%zKXU0u9a0Tn5MDr@3rP)Yw6p zwYABcZzPD#IrIie%bl!phmzfWBI?9~+C7#A3L+yT_x9X3zsTWkFZ6z}6^xJ&E;Vja zvmRaZ-4#8t#w8$_Yr^UFYd_)Hj+A{u*o)kH{_|F<;D)hQeo;}jkKJgEG%v}hrJ1>T zoZF@c`Q~s!zU2jS^0?lG^7qk}vB)aDUZRfrjn<3&vWGaZ2%(a&uGyX*ubq}ZUK`KN zWp%Q7a6EkBlr?gVdMx3?kjreGQAG)C`Xu|;4Qiy&Qo1bq9!&7%7$`;X`Y{S;(zSjw zDFw z-9taVrcEiZ;vFB$XF>`2ogAeI*!=jCtgWRbBi8^|QtEeX^OmV&;%)KW^3a!kqC}BA z`!#V*O_Cn?Sf&P=n$mTy^OXfj#=glV*E~~C#~x2?h|jqBh_Ci<5MJ_l^}Nwl8rcye zwu!48dVwy+qiTN^fn#-6vcSz8ER#xbv;KuxheK#PjtSl9jlUE zOG^vY%-B0gw!GO1pTiwZ^H;BRdbjqFj!OgV@f`!z_Qt`nYI#M)#jj@Y3FW?@7n7al z!!=#$Q9YOJeq8WWYz82anYrZA`UhB%t5Fwk+=TtO^Ji~1&Iaaza^c2ITd6_qCTzo0 zGw1LrV)5gjJ+rp4;kbHLA(~eCUcP0RuiVXwxN%E{;Iks;bMW1gt9~7WIx103AH{MY z&D>yg+AX^F+PKMgZ+&X^-oZnbB=^t@y6WQF7x0cZKXauEIR<836tsP@&>!mSaQ|p; zV|K=*=uRms^Vag$7z3H*3_4USR1S3Z{>=S%>YlxI3XF)0f-58TO=FcdkDGjtaVeIl zvuc%Vdxm73Zi~Km{`KS9WuD-kiiiE&t<}rR4M{dTj}zb*?$du?{GH38f_oB5}{q50xr zf?B8=hpG3Yway(c;AsxPOj!&p-!@>Plh`+F(^eOsTU%2m~xrDxdS zxjmO;3_PJ)A)AK^fs#DMIXOm8BNPX$-AaGD*ETtMzgYJo9bLo2e%6D+&*KeVES}h{ zH7deZawh@PeGx+fksEL##h6Q7js~Sh4bS4^0Yd@W*hiY!+;#KFObeOKcMCRCRYf@B z9<=%Vnn$r++aluI|FT*N4ar+*z@SQ9zB{^kZXuRD!oibjZOG@Mbl*N&$W2Mos!T4bSHt7mW#Q?ipphxBC4NqasS|4yMUE0%efe zZBZO5u*!Myt3eyDNuskefzK;N&9l#5-AS(B7%a=3W4RjHdiD{S)7BT~vjeXGpOgI; zhcV5l9}rjF@h#V^tSs(Uz_@a_g98KYqSxZAU>_ur(au#R@%U0$0M(X(fq{eL^AgFE zi!WJM94@zUIf&dSy?qL$siUKVNNgQHN`Z`uN(gvWy6-`UW4`3O_YdDoUJO|!TSruF zJG#25l`axo6g*1V{oqI|V>R0zSFx(@cM$)?Q$a=L^H~uMCUy@kp8Mgm1USCyJ~u-! z(tESRd#|_ffc+fWi9M?Z@lSF>V2W>8D^LG}u0JVyduB^0#acO$nDO zxz}%`A;8@V#B2=;nan~#9y0I{v4}r_KR|?wyD(UE$IDC9Z-_`@FGC^wjUMNb!jou2 zIL4LyFKI1&X4oYTLU)QE9_q}%?pAKmwFK3<&5>C#dbG(;GHnMoE8vubm&EoagNUpv zhbK-?c4spW4nmR5+is6}GvHg^EqDeMVwfnY(%?s;8%?xw$!+&+_Ew z<0fXVLt0U{NL8=V8b@DW-;qs27PRkNAx!=Rg zEGSr2P!RrwkBtq7k>6{_)=9)}R4BLybea7Nu*H+e*f$*uJ{oN}bPn$Mg*pwWh@|Gj zW^_5)a~z(ES9fCwHuBz(@8dOjj}_b#{a(iDp78|tgO6d?*Z3B!CaEukBw%uB)0>Wt zkE;#6*zS6AfuSO%2x;shg-z7VM|I&-6nm}pt&vh1xbkf08lOW!nS~oo`veaek&f$= z(!-gRl{!U(p&=o7Mh2|*x5(DMSK90zt~IH1wNQN>8e$5Dk$S>YQfe=S8$~1VbRx5+ zhDt1m2+I_)gzq1#9r0-sa8CT(K-vvH10_9vbp@IhJ}MHKT>jYtnmZ*1Q>Z7#J>ixH z4W7^4u5fWF;)(;&eJFYAvDK?cBJ=9is|rg)!!gh;Cj5Z&|C%SFmw0)vck06v5*c=O z_6oMvn#xLYIN!$*@~#tm1oBnmcU#}ZS4qS&JUl#GKlGY!9TdRb_Az%(kcr9q{x{^cd9(4c!ngt(_Li$RhNlnl5SNR#Y zVO_s!=O9axMhW>I3CUQ2Qd1T7qU(p^C6C~GcCFjDZ|mzv@H9HkU~eOw(&Jvf{6aqk zW#1va1!wyG(;qS@4UOY76!mTpW`AW>)p!0e^&*K&@7DQ+f%HD0?V z3fYVOc`=iG(KcU84C`DTf*b;rx$WX48LR4~?9q=@dtwZ}B;i#!Q{CHBR z@J21yGXoA1&bF@hIOYzOlp}LlQK83^SKoKbC(U17M|cR8lYY{%84f`P@TjS(uIw2c zrP?4HN!o`ab#5Cfb{I$XLx1Xn`s;B|hSBSYpuuGl5 zCXBYt9(%{whn$fggskD|XP9?L+?09kXt2aS+`3OqHw34sL;@6w0tqR&XMO4e@RD5h z^pakyihGZgmGN4?*$T$*erSuPI|NYuC0()!MjR7|aAmOQ>tst1-U94+PeMbV#WVu8 zU5it^#5f_2vrByxg1baUGdMU%6BYXU#zDx#tqf6n+nT4`#sWjpEqr>~9~<^-tZ%&= z;^S@=5D@tFqiY#f^Sv3lSJ8ouS z;nhBncx<>DwzTfwXJ~VTiPGROh0*3XNu9u$x@H->Wu}|%JsaSgBjeC~>W`g{OfbD8 z-jwrEtB}Y&RBQHmcu}Z8G2;87=3Uk=PIkNd9y_Pj3<%`ZcbkFU6+j1c=F`I`fAB_O z#(>q?XPE;_TC62BLlwMcYl`M)FlB6h{`+ZB0JnRnWvQlO`JE3bZVBNwhvlj-=0**Q z0=2RW&OXyBQc11>2-6wcK>ytQJ?Fezdb;IlDfatGYGi`~U6&Do&9EkG$tvnMPANWr zGb;D&vzx`&&8G`ZZgI%&_})&$D}OoSW@e&_j{be%_Eo?WTCTJ~wp;kV4V-(sbQw)Ywrd#;4&(E`_AmyeDyF70U8y$=B}^j_CLAO+JL~ z@9%>m{qf_+#Kc5Pqz5)*&e!D|kA{PJC>oy9t7Z4Dui4(acaK;GMDt39gG|{c3Q;t# z`WFEJS6g(^M0|R{Pjh^H3=mDsVY1n%!SmYPw`SW*gK=?jpx_u(Sdp~87`N2pOdJ>( z$jD%5FrufVgnLsUElbz8v9STC35IL``^nx+%)R2Ba+KRM{ioFvz9aX!7q$;TYunjz zJMjr!n1t#MMOs2aVrpuN-g_OrRnI?y9)BD~+@mqV4vg_>(J&tfGQ=`f<6ims`3vs* zAc?)o&26>f2crHeFE3R!S36IQ8W9R+3_nd2P1Fy7kF&c!CnqPb=}Ua1>NkFQk%s1V zDd}s>M$3wd3J~ZXRt_&MS^I8*>lQuZFVkVu(L?Fm^WEfF`9Nt=;z09GH-)GsgHaIyKCyk@3hyO?{i;f zWlc;-&||~9X2*nvoMJ5-qtzWmZhW^CU45;hRmo*gCXr z%G#u9?z+0V1_rbZ!I#R`sQCxMgsBab#+C>{m2{kW7rzPZ@DGw z!;galx5sKkXi0wlU*dlF__uFLm+m!s?}Ma%OPiGLD0_8ef0r6mNCvKL4Fmr3;`hs} z2fp6eS{;FlOJK#rv14k^IIv48up}t5Mlo>pT2&6ueNH+B`l*n8c3J>dN37kY!!Xr7 z8<6!Bey~@-dWGG=b$KWxBxLaG4cIKe?UBKSodnC2mV#nu+-prhQ1Gb{iypm}Sax0A zy}bUpA3su5bKxF>TFPJ>x|i{8D>5*!7&~YR)I+Kn@EvH|0H7&%Jc4b$^4@CTIefJ= z5uLktYkdyez-)_Wy~VWF{8;Q&c=jj^ButQZZmYTM;e@{L8jVW7&d<(PR91pVw*;Q5 zFZL%Eh7T)VlXUj1u&La&#J^U;0t@dRvV`W=D$IlvFs9VSHiFgiz?BXU4+qwBBjEFH zWVHHT!t>`*m&EI43`c=wg2N0?cD&Zv5_SO~m&b>@>99$Hshp>lHmtb_p#zbVC8lfF zZf#u+aMA(^&KsoQZ{NNV&V#Mc_2o;BPU=xe@bTANPKwU}tEp*ezc_-n7PPxMqUcnH zjAOVFxdDzlo7zh%V&aTJ>+Gy7-BP1Rf~g%|Cv@W=NN+A=#}Lx+FMt|P?u~ZGWgRL_ zyt<#foSf~%2@hUd8;g>ESE1(JyB&VcDzSVo>z<;eF1@pMLy8i*ht6BK8T?4PZYYBr zw|n2<8EvW#*dOJ|FH~NX^WjQaDB}CF0tcsYSP=^V2Md7iNLyRmKI7{Wvnp%u)EDG3 zM0RNHwoh@8ExFf`NrPbiL1jw1rvKyp!0PR&tSlx2E+1rh9gX=ovZsXHh9{d(BgG z-v*$)eS7ps9tTw>k3IaH?Y^NvzKNdXW&OJKOEqHoj)xpHS&k}h1e6^ zSVSG+m=ZP|M32s~Bw7YuqB$q_K{iBNe)y=6ksEO$%UkZ>v>1<56G-}*PnswS138uX zzJTe`J%QH*K@ykwa5u*oL2-R9Typ*cJIkB%nxg#XK<*u+E$`yR7BX5>J-v_+8X5|V z{*IA{yzY5xg50o=)*-9S^(}m~{^tzMS^bIMno~JZT!3v5<|s*63Pthdi7-d@#Pq(`&tx;vmuVvVMAB=$tQ)7hjh@D zz=qEmlhlSxfrL*<7<4`ieb#>Z>Rf<1BN~zs-{MJ-zok$l;(BZpS}{#l6{9{4u@VW! zZ6En8Sq*)N6WPWExXt0M7ll?nx{^+BHmQc;y*);a)9Mxp;;w0ZM)gZ9EFIbV7o99H z-psNwXc(VhF=SnV4Na4?ryUD@xv-_0fK@B_@~A@dJ)i23zyLZ1SU+f-3s?Ejdkdu> z$^I~7c=-iOZZJt02iNizn%IXFyoxfJX5B#z?^A>>nuqJ9s)5}lWv}MhWEH>N zMJl^qsBYG#K#oOK(LNLCl)dfgYSoaj1?!>Fm{`Lh7o9~^d2ki0wVx( zl9foTbKBG;GO^h1p=eK89w1VFJkE&Ygy%~@z9TxdNk?PaF5P;>8cUEqQ3&GX2q zvg-i>0SohzXEJE9=3nqwKZYhsAy`9OJHD8Z%9Jv+ob1z(EZ{EKBS0K{qFY4AYt|0* z6;c2^ty#$tg2Ob)RU^_^Izd`mQ|S4q+yxN-mr1FpYTQ zhXh!M6)YlGJOttkimR+~1mpE++f& z#O~1}g7fF0017v4w9)%PgeKjmDt=U}{&;5uJ4m|pE8we&>gr!>d~!I|tj(xo`Y>AA z!7__1Bn2>oVp!Ef@)cn>`1!H^4TD}T<%~OwJgeZ6O*%!o$*Q>^n>x@wp8klZWoGO? z6;fAMNAJ7G$iOi9f#}ycyzo%6N-STYUcwxnzk%&jR@H1uN=oKn@EITC3%?Na*u>|m zm*PzqakbXg?gvp5;wgX^WW;3?La(6vb_YsPndZ|BsSfmGER`1sxQBkI!@|b4=BN32 zf;x-2L^?{h4E6MAi0CRPv)n=PBhB6#5qbT-sgYu(U(OzraxaCSR*G z;R=^@GN-;_n2-fe8}%wYekHcID~SxjOfD=c;%SwZmY%IFfN4BGVQKrVEHfu3 znBuNe<~3BA@8K+5J#HolYEC9DF8mt^8np_{2_;(=)x4geAqraBdaGWh;Xs~$z^{&% ztYzN&n|bNJDQb!?4w@L=az|3LFDeUrzkPcV8_Nw@mF3%+pXRXiv?u1swtCQEzEP+R z@GUJZZF!1&yqg9tsHv$5(3WZj;PmdeSLvHK8$fl9N>Lph55b(ic5QIcW$PGma94j3 z**iMAGBZ;Sv=gY{(NSRZu2?z_elA-T15jJ?-`HePg z3z^vgmO`8_^DSMxZx+6OZM(J5OK0zbgN+Rlnra{{GlS0|6%wT&JN^m;(Y<`lY!?wj zIk}H;+J4k6;VEjW8Mw%>Fx==FQZh2jFE6CUg6O;JFemtISvZ>=;cy_hV`E_f0tJ8x zPDW~%#WUeHN05SJBn}oJqu<64`xipCtAE z8Eh=nx=_crTQBMv6vnw6l@o1sqdGfpp3Ku3@M=?iOaXkPKVMKqv5u%@|5>s>{_e3o zcor}}uOpf*2DwwaY*~NEY;q#b#opCu5y4qU*s%6YBLd7nC+;5{T-UGqk{t2K;Dhbp zeLw@@GmfYM*AL4 zJW2g5qgd~aOkV%~-X36Zr8+66yy&LA?1{R(L2J_o585fGZ(eG)XangoxCb_XRPoDV zXkORDWdfa8pMI*0Li=6`tc(UK=d&Pef}85kH|Al}^F zRaaA^u+@if0OO`B1B7<;%Pk1@nOOb&P9cUwL@QJVSw59S&btkst{}6bkmBbib`>#f z_)|djk&TB8m^7}>@%Gm-BDpm_P6`!kYikXSSfkRIhzJf24(2JjYWb|>W~9o6kZtq? zJ{#8S_UP@`6_=jDGP-Qy4bf5%W}b1mt$u4swbj3^tJ~^mpr#hxVJ70SX$IR%+YOS9 zrux#H94y9!f5-q?`sO|Pknno=u%olH&$<${eC=P?K{QcI<_$4wa-P2) z)FRbHL~A-aG!#lK^7tq1A{jBU#_ij3hw&gBlmknL_$$5NQJih9^l*od!eb0gNK8;t z_|i~P!Uci%cm90Ud!z~mIjwkz(~m1WYzLTTY#AL6cranwG0sM*g$lTqoT6g?a(Q`q zc6N5!I^yJz+J*mQH&K)l1`TwF&d;BDT0y?=>gtlm9jo`ycG15~lSXxErS>Dvd&y9z z*1V})Q~#AS9fSgKnUp3fzocYn(FLM*tnrY+8@OtdE6o$W;Ih`|#$?8@g^18k&^k zWaS%W%p+Hny&n~RK19sJO_%9$+Bfc70D*3E48kEAuePU8E?=lp!k{gie};xD9P%%# zrAX<$kRFTI^*2YaSjQ{QgUouH>`aao|*f_v#1-x%OJfDppWg?x#Dq(x*kAMXZPDq)=)yTH&~N`vuXQu4C1 z1>J&Kl&Q+8PhY`w}I9CoR6t$Q#A78Y~k;9K?PR1|lcTi#rgU-3g*d(9GP)Nx+(R+TGK#)n zfgXsE?GAh(m#a5q`&jf6gx%6BUC-qykM z?^O=6FbRD6t zc{9r6sV;%_MeEC1xxx{JrL1U?-QaR+nlN1JJwyb`ZyfVU(NO~jZ2z<4t4Rf^m@(b| zL!eZD-FZwUx>R&A@_jiDN<$9~*Zv7G4N-^s6GlL=;s3iC0RM07h#8%1fImOFQW>77 z;&PWXrdo8Jluc5v*yM~O4D|&-J^pv=;4P%Qzcu+aB}lWXy$pNp3tL*G0<%nhL4k57 z1K~EcsGF^>ZsO##>FH_knGg5&wtkLzZA^cnh>-7Tsnzb)>n8Zr)LFUoOEGljCovjo z0TNt84Oj+x0+9UzO4ZfgE(9G9Ad!77)`yZS2?^hysvzlUWLZLNLHBrf9&%vO5fRL7 zP)VFT6>i;%Qp+2uco+|L2>gHGHGn<8rY-i{wD4UyFF@;WnJ;awo|auC_778l=mCgq zrHuzyTWdffVPLpF^!jdNVaK9O^a1v4L9^~&K zb`d*MQ=pv(66g7!e6S@vd-lv~0Tl6%ALTr6628uR$WP-cVrXIU1I{KRBcl{**h-36 z9xW&uczj*Nz&rwkg=@S$C1U7zbfTU;BMpu%-n|6MwTKbJO=V?3v^+FXfVH7tgf)I~ zpg$Q#6de{@Wc&${d{q_H|yLZ$#M_adlepp~K%9i!fb;eAvzDBTf|0E>65ch}&Z=dyn1_?Mw>Kd7 z)fgU%G}aA7cCQkj!CSNNExn@+I`JyzimRdpd%1XEBwGG{fu4% z+uR(!Ad_EPOKn>3vZxgt`|~6wCI;1$DJwe8VN_ui*K&UW_CLr6L&D?CIbRo--MXqt zk%g3=!1RL*4#jl?C9w~^-X|L|eyS<_;n-<{k5ck2q2)(>=bLGN?k$^#4>Qv`0v7ns zt<|U|^Rj@L`GB)!FB(~Q(?@Ye#_tez&6QsPiq9`k78dpn4GooBs<)`{KoXpQfZzG`H^EOMy!yraQaDM{^LI09l7PdIp*p zevM3==sKjoG3y|0Ne_#>cq2MJXQAxO?5LuTkbK?WR-!Yp$UiBA4(08?B1+-DZJS|Vh5@{CH61O#C1~$3_OU$WmLixlSRW)qh>R z4;YMFnoS%DLMrlX^Sn>n(*z4K0ZD}R#fu)Q)X%8<||;`w$6e9iU8_!tPhV+Wo)D{#Ob zE_upH-H&`Je;c;ayko-Tl~4YYFUvggz+5~mFW)|`_HnhprF(TFQe0HAD74pVR_JHc zjdAy*4Pyc-?#bfnai)=^d-g15Z}haZwSxi!w>*6e3_$UvZq=)ZQ`e{ny8nx%H!3D8 zJNv9xiT8pyMVD^bRNwzY_chFd!`$miZw7AWzc{Onabb4CI`{6;kde*6#JY6pqy>lG z#hd7n^p{ymzhk2HlmP8uMBfLjuz!?;ZhR`_HDgG?`H>h=t?uBVo%uEkx-wv9(zcmfSb*(T1#$DsSBKlvgNg|U_-KbCmH73i zsm(C+|MEn!{^DUJbxw2Vzq8;mx~zQT>1#uwN^5FfK;uD`p&gMqn-#K_#4u!GIy@CxXnRU5W14-yPTm1Y99w#DCD8_71v%iXoz2 zRV5hQ1D2Cgy1&0aj0I%>zq{3nClqIZ2WRo@k15GVLdOTl7}}GJWQeYC4EJpmQnon` zRZZm|xJU^(aKJ*Zo(^ewC*KS@eIeD@uBf=UxP*j}3r8l$osxv4B-2QE_#m*UxNVR< znpJPs#i`qWCYwqUZt?l_!OqKL& z|E!r|nX2CH^@y{#s;(kX9L&RfAD|Bz@fvb2#P~IgXk7xWPXH%iA;PvsPDS-1-I$^7 zxrTI$ZcvNE#`rGIGJCxTi~-Bng9s~tL-NY-?{ax%C*%S8kc@uc6M?a z9v+73>?%U%AsO^GOM0>762=HjG7$#an&*I8^f%s5jxkMI4KnDgKu8oHf#9b?z*v2x zim*Fd@Z;XUx*)tCJ%dejsos7Xf=oN3#}%XQQw$FDE6zPJ=&@p%{8tpHP+ znwkPova+(WuwdOEy&w~2%V>96$*%wXp8eHN>Dk2@bX6(;WbA!{E-vCRs`IAakow%r zECrQ(bwrX?bMK-~95jFgQWnta7<1zbxst)dy%7*%VkiX2^BVOh4qw+o{=G0q7qjwblBD`bxcs5x*1#GK!M=DIy1v;^?3UB zB=vwGtBeE(a%=x~uc8{4KdsBUCoam>zbZY-WREpszc(J=fnHr!+|&-4ocjN$Ow7$YpPyg(ntt@*F$AH1d+6 z{5jOZQ)00aTJT^x-z0JIPVnWMxEu}Q=X0fFN6TTL9D*sfo+kkr^5ERWUH&@@;K4x_ z%ioaYRdn5~S5r z&MNRLAx0?*`3-&cI;PaWg}%ce>A^Bo+dKMm+usK$#e%LGLSyugE`2~Ouqk_ky2`Gd zy9eR)M(^Ze&Ua}9?h4f;o~LM&)V9`OKPFy>fK3F~PS49P7S6YC53GDISN{C(|h0qoa?lPzYkN{_b zhFyAGQ!)4T$=wORbgWefd4j2~`~>R3k9o@bk;U2ox^Z!FUkKPFLWCS}IfzwWUS2?O zR8>{Mr((dW7c?i3)42wh-$`(G`4}K%aY2*`I?c`^zBm6l0EG3*``>F`RSDC(r=(t2 z*x8{8`=4sqXipFEg$qy(?0AzQhG5Q31*q(qy7koi5P-}dsFISBY$}IgcpgMTF@u4I zIEDP#HA~^X%EMQVej;F@chy(;e!oGiRTTt3_q}Oegb5i zvU}ehMTDH9z46%4e3kkPkwPM*RY+7cHNk?^3j!FBqB;`$Pq7_a2>5#_ZC#zFhOAEu z6?Ez{1xM3~DjXc{??dxCUX;?vs)pPn{BqCHJl)40iX zxe8e1$j#^Ots(f7+^yh(Kn(fJ-GiXc2l`~cFG^=>I6y8y!w7u*R4B9^X47nVZIBoV zgTzSMJRv>|yxS1+jr+zlgt$#3wY9bLRFh@;$7-FETJC4$&1RIX_k-O7fn*8_U5&EA zAsxVDDJk5o0DEyW0r$p{U|?W?CYgBM@F{WM*eUpgQzPUa%2%&kSpZB7(WPUQUn7mM z(=6n40Z0R=f5dTRBl5=&izRCC-?p~5=b9+kUJ%-xX$8>qWdbh<2o#$dpgZ$e=$yAc z@_-_ub!(Cu0y)q_>ajg|ho@CoSQy?W!9TXLVtc~gy4U%f13DR~X5Kws`|;xkQ?T85 zJ-eq)67tO-vxo+45`7@^TM4vB`zSx?C9H;K%rkoCck(M8vcnKD;--nJ(qcjOf>>roYELx!sHmu%+5rJF82m!_J&}6yFC#C_Ecsw-#60e z(_L!lrGu1=Bo}vn{epT5 z8B54xaoh@`<-c*mnO1RJ3Buh--J;`p$y4P+Jsk3FsGMN#3D9(b?JD{D}oV zP6a(7QumO*KT+k$Alx=Q@$~zeG?13tMg= zT4bH3{ZYf6vij2DbIBP`6wp!Y8dJC91e>gJ5kaT1UpOc24`$IzGCppq_Q+-f3CVXT zR7%w)u=$Wd)PV@}e%ubr)I7TAy~9oA*D?cyx2VNFFdFpS)y2rM4xHM!dN8H0}eLX z&`9I~QieSUP+-M{ac_LY9mjNeN)Tgc>D{#ph!r$A@1GkEJJVKq*)XTfSQ!c%zX(eS z*#J%%Qq2eS<^chdYnDIoJg;*qUwy~i)se)c+k;e49wpB7Dm0uF4?W1oeVrtbnlz7OvJ2yFXH zXAPe)($owfwto0<>c+5SNnxQ3?pR4_^+eY}?;F!LcoDc>sz3c;55{E3?(kvbdz zYI%gaF6beX)YDcOgUf&&%h=i7LpSSIpg#uQG9!{^2l*4Iy!tf`jIDeB-8_kJ->k&U zYW0L56~ePYf|)rR*r8v#<3dlSX0`$Zr-9T#1AOa)H}@l9M+V0fG)aAaSqoZiK_Z4`I*1VhrdPndW>8ZG>-EZ&E8^l~X1r-4 zuATR}SHAyZY5msi(+a0ZO-X^(Ne1Bpk6!@(;q^JRZF94;FI01(KtK=;9B(K^kO42g zSJ`RCODF6UJW~S=kw@v4qm5|^3H;Ur`H)zMd}GCWc^*Oz!0~vx#KkRtM;zHbu8LR;_i3C&fZ$%53-ms^jPsEX+WZ%nmk-aHrn9YBp+#Gg^;U`;S2_r!Pym9?j~Au$n%@Mm zg-&kEKd#V3Ftw<#5R%AL6cmD>(p@*!B1^;P7rE(AvQ2kuWcd)9VmLP-!2x+&=)}UO zygpj*p#s;?wekl)P|ZM|UVkkhKIs{EE9l042a9ys`*9N16d=@u2RC|G+&J=Lkm?A&lc=`;L#- zUE%RU?c^|kHwW6?sVDm&mY==2W%uu}Nz>H7g-v3HG4a%`H?rg-;PnD_V@o5|Yk;~6 zEN|br1Mf8&9W{vWxNT%)$4v!xg!8|~ZtG4@k0TEb;Js8N%nJ2;(-EL3skXoP&r)ir zl?K;3BGU0c@Q`7KIKm_eIJlwMQ*m5mCY2}6-e<1UUm&AEyaD9u#ji~#0v^ws{z{vy z-TsfX3AyRZ#KhcQD=e->swjo%87(cXOFmn@(m~h_hd!avIoV?Sv++3#{S*T9Wp@Rxa&YXYYiN{9*`9@n+=5|5C3 z=zHEYVdqfqfy#!4vwmMNF(88_J@xVh9_p{;No%BCi82<$yU^?+MRb&dfM#18B$<5N z-D@Ds$8XgGVi7HUvrXy!-vQkl*UtHW$xQ(Yw1jcjmGrM)7GL}y@XM>)h}}mFC^!G{n7n7F{4f1M%&wr^7UNE6P)8 z&I!{>c<;d*h8%!)0jnDt9K4IO>ZCQ4^vyam^K?z$iEg4LT#~n3C+Pdfy)Ch0Du~Qv z+ywLD^GS|-D`b88`upuiYfPZaka=WjE!xeOkTw1xyo~~6f3jBh!<`t2+?`tvGgRw5 zAl1Ld@8azI3;JX1eADQEAJcYmI(!v?;9&jezeh>R$Lp0`4l@=O7QPz$rCBM&{HFlR z4?kfXfr}?qN?CMZUjaL@=t`MeUIxX?rr`}~>x)n_TG48O{w8?A%URA#^`osIOv>{o z7Gi3Y-PS{)ZF~%JP%y-xHoBOy_zHQhYz?V0D@3-VxH3Lp z5fXky5Js2U@Qv3%b_Iv-d$#oXF@W5 z<4|@vyV(Lu7t2$Y-xEYLvtbeq&XJYm1y;vDlfUQfQsUX4SA($Le&37?4#wIXD{(Ok zu#6?ld2?oOan_~9G0=*;+S%kn&lOYfLavt?{aSOglnAGAnIwDfS~mGurSbq@UHK{L z?AA%YfpQ5L)PI&XBZ%t&uK4}Rx?W90+OF_<8D9QDEaSov0n+9)HH1-m3B8#~ z#=4b=qmd%;EMp{3!icS{tTJZ2p$8Zun2YRZr__WwUKvi5IR20O!%Ns+(1zvZZS?a` zE(O!W(L&M0q)mbhRPLj$2-`>WE-*>%sfYpbY-=oEO&ul1`-UcF+GZ1Vpp3Lz%a z)#hD9?`kA>>yg9Ox7y-lP)12)fKO&eaDg(?bdBL*^*>JUsqlEm_`%tNry?K5Cq&~- zW%8^&YtZ_Ocg@rQ_g)*Rj%jb6IGffC`t(LwbFe>xU`#^N;%M;T!8G9cb{}j%vt>eW zR9R(OTyYOP)-$MZ)^zW((XiF00`)5A_w~SuplG5 zvfP^oD{3EB)VJWDa=L2vT@_HMU{8$?gX#kA?$HP#8*kh%(%*BTqaga7DZ1HXGB-Q# zb;Nv4htKnVeQ2N01q22i%;BR{;qc~{(fBypnBVjBS+A#*B8)9afVN9a&(8ia$QhFG z`bK#D;zig^0L{pST2%g-&9AR6sv4nvr?&ptge~^rIFd229BbuwQ-YuWdS){aNtVCros+Pb|a`f|b31&(ACUf3^4B z@l?P4|5hBELJq<~O16VaR#uUaolWWpAtEy)9T`bdRvp>0N2TnM5$cegnUuZvDBsu7 z-F@HR&wc-XkKgx?-+Da0{Z%=~dtLAAdcB_OQq+;!#G*XUf4T)Qy|S|M_lT@d##9=) zTB8Rsv^W$a(=ELKqCd@FJm3x>VEn+LfA1?(jPbo!>DowHWf{Rqfs@34^C-A!t*y~Q zXASb{thSp5tXcx02KT=t3*5z=3Z|B6)d;vAW$@+8?E5BNV65Mtn!kK z0j=;4pF&y&-On<(z|;Z6kOToSFRXhZf~slu!(RA7a`zO3k=9?bSze_80Tf#0CiZtX z=z2}%ZKE5Zlz#~=Bq1Q?`R`uPYJ7++YkOGk;={xvp4cY!jFjLlgZeMh`eaH^^uFg5 zXb?qcvHh0A0AZSpDx_6}ZvYfQKsA3GV0#SiIkR1dGD>~CtnVj9Y;`Mt6d6H9dOdU)!ypv4kVHJ)tO(DEyjd$4R&f$GGoC}lzxzJh zgzB>TzDt%vR!lfKSgA=AJXAw&qbX&VCqF@BR zSoU1rPexw83czs4)${W5V*U0{UfB0s_7KLfdLq2xAPdWz)Ix?U6{&?Tka`HTyUcSD z0ASP8A&sn^RN_-#(Up?oVzI`avs;0ae$bC}P2B>8M?IDn@VofaZr5VfNTyfRi``%Z zM6yJMM!^N47$Yzr6POtpq5b(u$VqE;f)^b^SiQZ=K;`2;9aC%7S2A%SqG-~u5lmyy zET~&_oe&XO-`H@zaRWj+f16oZucUUcLZ^4NHKgmrB(ZuZ?gK&w6PD5G4bH8-s7fg@had=J!ovfi8%>7F}UsLyzO; zHMlDf1PV~eBw!$*$$>r@RO+x2^90}8@Q0=wOLxS+6_7$$c!1{fc5ui^N*cL6;uj+R z##ktvMOcEB2BsiRaCZZEI^s2P#GZLIKn2=Pun811$0VV==m+g2d4d5?ZdL{>s5&Hf zz=;{_Rqr=MftxvYbtkTq;dMgWIZt2g0py1PdccO8W&p;29EX++kqm_fV7*5nb9KbR z-28z!0I&!B=qplE>Uw)OARQDbX~*#H#NQp8pVW`2^85GGDXP3;40fL-1MJu4W5z#BZ=(#Tq1S}GzWlv`C* zYg6Pnu+FGt2c7fkddjoBeV2(g19QcQ}e}QLTi}GNS z`YgO{2$buYAn~eyFI;&7`rA`*(|CA-zP$yXIud=2p@flEqjOyzpOu?CUhS-c$;Oc` z(yZCdd7%&B7iB-1#fm3RgWO;GklT?>5j7J0Bng9TE;sQLh11M@cqO}Q-56Ed%4@Z&zc!^Lz~K&Hyd z`Dh2@AEgRHj^(-0UyM}rM`WNjJpNn@^taW(v>OYtq;^a$EK~!}10#2Ry4wLp9V8h> zMnpivGO-UBtja4(nwlOuoXhOdwGs24%&TmQiIDwbZG4ykK=`PFW!ztNC~5x#9ZCmn zILsLk=+Kil0OY;=u2_;UGdEZIq|WYwY^hWo)VtsvxPVP*N?G9<5q}aL4Wb;qf7ScP zu0G1SF9#Y%?qG;o5@u-yVHKkiWaehzPziaH@3-9enr5>^n;-Q5<#Z=LsAt=nn;(hq zE_0tD=(svAhW&+sn-cwUyv(`-*2xfBcC~(5E_pMTB$N!(2)c|TkWOp;n=*p(hpOzi zeMuqkOvUsR@9clGdBFsYe6!ZY-_CrxKhAuW66WWp6a-z{BDaGE<1T7OWhQFXq6f)X zuE-y!)EWP!!!o-%L^vr05c{b==I>Ah#PkrXDN9p3NL{rT z-@-qIgY;zZZ_<-jd%vY8OEkquHB(b|rAdecOVd_VRJ?SF5o9`!s>igH+etmTG6f!y zLis;Fm7(`Xe-QBe*s+(MCjT9cMz~3reyjbCmlM=}fUJd#E#!55 zN8EDpPC~^U-rK>0MgxZ9)Y1O_ewb80gMP@gBeauYHQ>nFb&c_WfBSR*tAUOm1gqdz z1d>VRq`-;eefDCk&74Ev68KGy-C!Cj%rbNLZTO=F*yq(?#VX31+jCeLyqlW!`IkTc zbDAgA`bv#gm4rlc^xs~;XVTnY5Oq}OHFpYQ1Fh26dybS(4VvAh>{*B}A`jhHAyuh3 zdR$}p@Swq?t1oLZYF;3$J5;Tt8t>xU+O zYQpQ&gwL`sIv$njc24!)#tt$&c^o5nU9}G+D`0$zJK>vKCh`tbXa@~}NNf%yVSIIg zoY}1fWOjG9$e>So%_YlA?0t1i?&MP_Z?&iz8{;F0nynwU=B^E4%wTq)3rQ_3)R~Fm zdDsMD)_59@Q##RUFp)zQ7vksCvcr?EzgCk1Zx+Dt8qtzhTVjCl6|lf$H5xt3OJfW4 zHw@ElY0937_90IP@{f=&oA$Ss|<3y=dHwZ>BvTX-IV6@{D^72 z%w4*S7|2ck^8Jx#Q9cfqipmzT^lQ*M?G#VT56`3)%Bx8?%uOOQqCTXkn(QWaretpj znO^t_41Zpxw-fEWQBnWha%qK>RLmwZWhR2hYROsaY*%ucfkAa~v2HY9cP34asiQ~z z)0a;Wa?0T}7KgQK#zvlv9bhmCEZrUyt4NZ_)h!(m7Av=IU44X*tEb@b)es{N_jjYp z5S6J^@_T1}94Ary8Kk(Go!4#E?B2DbUkC)P?Q#(Z=6&4@t9ist;=0C+MftakPUrs& zZ3Kj!^%;}C%qoqJtCjeks-l&{W`WFNAcDlq&$)h78);^wr?&#~S2`|vM;8m7sdlvD zhrov2!^D^JzE+3TPy`{w)(mKsn;Y$%oIW)-dya)3BU=iHW|1QeJ7^qok{Fd&TTWBK z6HJ6sX%&kYWOXVn&(C*)cU>#f4V3I6u@?}ur_?*pqjrH$j#IMsv&FnyDzYOXYx4)k zR|34WFn_A@5$cu6#yS zPeCTPfqkAyJ32SL^qpZi&RV2$HScLofj#^7k2_gnq7v!PKTIL5syF|){>41NO53IV1FFS zKbluHD6L|I8QPsh_H=XpYN;$I-%Th|szhXE<8LSz2(cd1A(=!59<1MLWYhtoJiSR% ziPG++=##D*_a6>}WyJ~quHtJH*S+u*0Dk2Y5tQ+un4zW6Fk&bZhi zMUzd`d7n36I{eClAle%%Dzo{_n50kY{qo_&Bi)BvEd|ebV_A?DA~+%s+9kI8IYixu zn}&_9tel?82+$g0Uv zHycW;UWQgnM-P2VA^*JDNu-JGVwor5Kn~pbB>I*dK9=zvXy1<7iT4L<@=;H#`)0GM zjDMN*cc5Q2kGd}r4%Dk?b|9J~Ku* zP(k2ZDjmO@vwm0A@QbPxNrx^Fm1B*6*_5Pi+iW>pEzKfi_}Ii)b3%q)oUr+Vp6ZOFcGZcHUQWTM{7dGprA0aBU254LP6i$`r_guY(8-3l6-rZ zP|~5AfO(d1`#!x>FGtiNJs+(ow!ZH(h~Tl5hxJ$!}0?4y2`xL%a|0aPz$dBVdC7RUz}#@pM_K^jlDmz%{)Zn1k%eI5b8} zON%bO>r7AuxyBUaet7ko-!5u)Dm?>9{lM|fqIUM&4;z@8I+PATX$~2Shq<^E{D1lW zAOmg>U|!JXg5JWpa_uQe?yh?yyszNKp7Yp&NjW?$OqTPZp{AF0jP5KO757u``_uI? zXWq+wE5XZO(A3-o_sO8s1~`{NiBo4gszBG<+Y7GW8w2YW7|cZZ!c+5=gFldfgr3fb03@`Yw`7Vcz8w@J@#`UdkTf zDv=rSp2_?4=@XEe+`-V@fv_V-ZB$A}tW1-o66FQm02K}S89gX zC^=5Z7*O{0-G$C(q_2+^iG;)q@7UJ0t%;-y(W~7?mLFpAa;f?GTG44^V>Yp^?jT#+ z+}wny&hEId>~?fTpz$=7H@W6JKJD%A-v^#)9n-D^;Umzs%OPR4z*PFf?huRN@IXI(_|OqnW7G>u zQN(G#ZOQ7JAmCYEE1s!3+_3F)h zd8Nzokc9(}E?azyL!LW$@K)zVvKoK75MDt+U=721v3IRtnnXx{9d4k%iGLAesK1Mc z!E{5~6gqsbEop3M=^Nk^yy12~8+vxy&3gj;C&*bf&dXnsjwI!MJw0jyU}QLgdOy5k z34BmR>2h?RRe$kSFr{!+Z$eDWkMVIk)ln&eWR~IcmoF{OgOxiaeSOBiqG(^q-tBJN z-T~86|9D$l+u-0J_=TY6I5E~N{Me@v3O6(wf}|lY=`;sjcbqRB7ts_OEGt!2cUqqc z1DOf!`1H3#NniIE!!^i}u`P_+aztTPUP+-sfF^X5&$ zTlj9VbZFgFLGD}mLKSZ?%s+)bfH?F&fH#Zm-6P0kI0M?Gv6rG26`u2hr+?{)14MIo z*If<%fN|H5%%UC?R$NNwAu;OVI%IDWTuKVIr1QvZsT{ykN}Xe?KlN33p?8qa2v5Sy z4CKpgXci_WzGKI78pqu>iA;J4#@^;;;|fpl0tSj&UZRUXNAtSO9>D-=X)T4zU2ly) z!pt1aSCkYBc?TB$Ki8mvhsL&lZe7^)%`Fd)`K+wb1q>(=7T|elUf7B&?FBX;=0ix7 ze^XitBVvV}@Y=ZI?HnCJIAHBexeMt@kScrmo$JwbeO%;2a9@e4e};F@{njmg{atz= z1!X~)8Bk3Krp9&WtnG-$f_62u$&UM=iS|N40+v9uJp1B)a>; z5WYQlvkB{wlYL5JMOI0Gg-aE z=x7jLE!bwIbO7R4!Q8ep$b?c^+7aIFQ{B+^Pjv@2$9SHJrq(xh!)(><=7+gPQi;zZTXjsjE?Os zl91`3E|Y4mDIauK3|E3uB)0GacsHbWWF3r*dNY&e0f5olMN{Xsn2Gel#7o$xV7>1A z+Q{nlA;Ddlw*0Ri<<>0xW}<%7ip|^0U4m@hSPQp@$1k1|%XiG-mzQp}y^9xjKy(XPWq)grH#p8bT0=juM0ZiFmJ9iif-!&eIuMZ7~`f7(N zAd^$pQm%>P(q*a`l)X1*IWdL1v?R*1!^!pUKe#7XJNo^HKs$OhC}K`iG+KU)+m_3P zO#U8@QDw7N&RYGBeDqkzEsy(;W$UsHaw_ohx^ns&ReWAlKY&0x0M_fLe4$CWaX%OM z0Nky^!Y1$YVLb#AyMU*^^!I0T{vtH|W7ZZ92j^E(!O?CO>MJ2g!6 z(dPiFzKc$d_kLMn&(u!v(O*1@ukkIszOWt)W4Nv#IdRmIS-V#DTXG1ey`$qU>>dVV z;^%z%RTGMnO9(>t)kw8J26HTZ739lM3BXT5HzS>R1CYlUm`lF^>QS}wsoa;+wX2zlp>PrzAbMZdh%Acyx_wcnX0i_-aO^>@tiRM<6sDe z36whnYY3<)^6n;j2IuGJgI2+Bd&)`Ux`&7K&V^ApD3l+`F+dqY6mcxfAKOf*8tN@R<8iTuaUgrkog^Fas?c5FI#oTW`d&0)uzmLhp z$muys%tdkX123%4Ft?Ycrt(TiKwfioT8y_WZX(Hl_^S&Io1`81$Oy_<$W`7vxEXN3 z+Mz=RrGYyyPCg)2!;(Q{HywgNX82Ab&vvN}%M|#?M^Ag5TSkOM;y<-^%D}@safdFN zhh&8&uWp=?pj~2QT&fM>0uy7jIqW(1@WF$t{@YQy2~VH$Z_sqV-h6x>$F%G<+V_b` zMWRg(&S@{ICF#B$^Ue(U^j$f*y!$7STLrM;_bcF7a6=KPeJVY2ahojq}JEB-w0@c#So4AoGc^!jGx3DPH>giw7@Qos)d|?v zQ(;rk`#5fSSN4u!c)Tq3N1dzpH7;J;II0v(P1k{(Y5x6ZBNVevtAu^Y4;6}eVYU;A zRXKTIoznFYZreEf|1%%V=!SNCg7JWWP@7y=Q?_p*3E?63oD)_Yii|q@p*Fmz470d$ z{}iJJBuLAl#&z``@7gF{=`M`X{bf{38rIYF!Ot@CHgT9gXET46#cGw&P1SJbs!uur z#b1Ins=F6#Tu3!Ha8?SK;A#5&FH_iZ^e1cH(%qG`r2h3L$I?Vlw&E zKf`1WU~^xRqlT82#cO+J>V_tG9i#bvg8I5@?#)OftN7Tv3EYaO?DCaZaDhW!eH=*j zO9w*ej+p4{k1u&b=?YPLu%A{n-_fH4fg<>+VWD9KDLx3ylKg*pZME`u+Y6)*+m1V= z#bomz4F>R=8p<`unS~%cb8~Z7-b)WIo0~s}WtWo^7Z$gN>aXwL{KN;lA%4ykW#D#6!>ez5dmCbWZVU|1%+7*)SV9T05&`5H zVLcRL;wr(FgKtygI#{+LGXWx8-~YOQ=*-(GD4e4Cfch>s%LfT{V^dS?)2GGdadP0< zWmE#0m>ee_Y=IXLTc8rzbk)!4=Bbap3?#ynTfo8qy7_B+rT`?1o9hD$E_j^>{r|qu zzWmn-#RlPxofcOyq4>4UYy&$YOFEBSb$sOzqj#x)6TibD% zN&j}vC7b6>EG_XFpvL6q<-O~JwQmC@Ja{UW3n2yk$^z?4jhc+WIW{ZmZ=T9l0a4ar ztUCp=?IPBGkU^@0G5bfx(k!%=l)C{SkPojDZ!V79Q*iOctkdn)@g{;kA0Whf7Wf z*KMiCow@zVsnof@IK89zca zdT8tS?3XWZp5g#bph8bi!w;UzYZKd33|#8{iN~RK;Q)zTzB$*DhW-@`d;74^PyrE< z`Ptdr{QNfqbF)8bK80b%N%yBn4s!$zgM=oday$A}B&uxw(K$2Jo}9AaVTB*}bxjNm zq#%(%JvswS=QqAcuFKs0jX&m2rj+cM9AeVTRC z3uf@pdh3jD&o+EQlbQTPKROMV#bMW0VJNzM=U(?7PalMX8p*hhBX-(*p;rgNUqE_P zN%XM>{Ff7U#&al`qZ{DNtb*1vPk7U4i%I5y^6XvKY;l9=VanoHM1UabeA98jI#J9UJP;>;4}mk-tjn;?)j~ zn%57AZR(Ntg3MOdwmAx3Huh(|K~pN~j%T}wg^_Z++-9fxbx3j@ve>Xu*w2H5&mKKm zdVffpRiifhL-2V=gFfP1b~#=m<5S&MB*6^A^g*v1h!6^ z;gTKn_W>_O|E&GP=E_d&&BtF+dggF_nUQLpZb!GJ#4yk3&#?_k=bnGB;b3SmqCpgp z&n!opC1(6|dWHt8y19kSiX?{fp$QlaXPQJ-24G8BRba3%_-G}aohkKTQj~MMv z#UNOSI(N7O%8hX{!OIdY#=ZUsHSZPTfLt4-iTEjvWrAur|spZ|zzNH)}A zurJ;VW$v3O06?#Z%A>PIEl6KewWGVT?pHzEDg~u61jIoH4uXc=IcKholoZe$&kmKx z>cWb$k34pTbDu41z(*H4kcCzY)B(JCRS8d&*&4z%kD#VD1?C%OVSmtBLK6?$pZG0) z4GCmnV`p!bP0h=@0sKtscPdGx#UH5{vWGXCRn+hS0qgrOK%TQ2w zPQT3TdjeeyL}d@mt;6EQ!p!U?ivz%`d{=aLI$DKjt$C`C%WLcM#wR0u%`Qd(x{ca0HZJpjHq_=X{6(b0YvUR}KM602+HJ zU)*u0-S}l>yup|VIvCK0&!%e|8G+Ns5b7c~w-TNMRY_lI-|HH|5N~;aBfby|eo>|S zJv$7L=lm~K2Bdo&RC+3EIltryVdSv)*a#HY8Up^$Q5!T1@!5pHL5{N3lW(h$)!?MG=Je$jd5=>wP8QdhoCTVB`(%^Z7+hPao^Uyz@lg%xn%2=?v64BWZYRa zw9jvzL>8`2L-4^!wZcqAMKNS_!z2pLCR8Ki4=$9Ck zHl0I&A%{(xVW-6B;FDQWA?yzT`EmZu~NBopwov#JsH&t2VY zszu7dCITQfBvQPV?>tcGASoq9kCaFQw)HG2*R&SVi|w+4jtJrobj?dciz;Cup;-W_ zfBo87fM`8xYHGkh0RYvQg6M-;51;>Bf@Etc3S2yY-V;&*VYeBk1GaeeB>aG8SvFRLP{C9fY}rMX}C z6DAtMK9U~gasYBcXa*Dlo=>3T02ZM92ZvTB8l<~^PGJlwEW<2w9%$!Ck`S}(XhA6NI+=QIRXky&LIEU3}m z02CbmGwJ`kZge!&0fG{#Y{yf@0uAmN+XvI==|G!TW@Ru$_Nq+n>ecify~cn;i9>Nx zRQRB%dlz1q5P4%yuv8#|0_=OOk~(z#S_)GduAOv@w>gBe{bx?f^ERy$>##P`P^5~& ziN-$gAbW}8<7;Q}VlQ2u9yjff8pkGkww&kKyli^Kjyk3V1 zG>J@3zG9b8Qe%B#uR0j;8`#)n0isfpDcQz>oltC1`cuOZEz6KLFepK}hghHCSH-^- z;d#a#@w@0aXvo4Z9SpY-6-TNSgkuzwsHhbqsc^{pg0;SC#e*VyyRB4wMOPT8&fkpT za{kvF>|-)L*Xl_^we~=i2%UXU5wFt_ zboea8;yjz{0MR8L7Dh>u;b{tCW^%d!B5yUKLYM4XGW~M$Qrf%WwYSI*=@^WRvWY!E z2}H0nzvlre;=FtmP^!lRl*;IY*Oa|G_>DQdv6L#sj-m2p*gm&yp`81Vs5g?U9$mE( zIRM`}z~GCx4`ivL4XXuJw(}|1>Vqkm&3lx`C{aLHB0RX&FZppR9dCgXBdQGvKv?w> z@nOHFzu3m|ZU~~hv6gWz(F{P023t`?Gj&t&1gFsa@A{=t4E~6T@p6WIvRO_l>mM#p z$qoG~sg&{U;c2JGM)6LyJ(LpG&94ub9=^qymJdtX$CW62@2t&4Ivl#^i5pQp$wr(7^(6M4$8uhZs9fF`T!4I6__!E$Cq zDrWMvX&Yk`m5)j8!6-`Q{ENBv-d9UWtXF9&J;G0q8Cz?I8;}qV9cpl~VAha30+-zD zBz}&AaA*xhewugEMcGqNhNyx&(5qjBf84)vPfpm7vN;&l%Wo)ES-gL)7Uc~bH**U! z8%_|%i;aJIpPgakA;_SHZ+9q-`~UBY&??wi1svIz>z?$rHdc)(SiLSH z2v$vSfax7V@uAV3Ng7bQfSw3ev!C&^K3WBoJ9Ig%C6)QYeBFC6wL)yE^V_dR(uu;- z(jJg?0DI5*ah={saN$~E^8)7o(W{1u=`|dvqgRd;@A0Yg1gB+WEIU91ahAFqxJiFT zo|)$keu1&O(cZ4N2Urzd$Xy24iRZUPAbsM?tLwp0P@IBz+TrZtgm*!8^)4lyEuA+x z1B&K^a)F#2oOXBbp$wnrODlMV%(S$^Sit4)%-1pK>=iX}@&-fGyL_}7sIlOv^7*oG z%c%y%f`tN$H0fEERhoL8yXVt-add(CX9b2{UDqS*5sa$d8CqC$$L_I9l65_djN}xv zQZzD(_3eiIs??9y2q;-N@q@MPUsT6m);{h)(~ygtdT!zK<#z8WujO&jr$Kcjs;+Bq zKMk_rtzt+Rga{99 zu~tEbgAU}Ir3238bEV}TetbzTAi$>J^yKE}=jY)WgWs_Ss8qqu9W`Cu&(Mw&;^<}v z-%-mc({*n2%}$pO&BN(_gUwj5p$wn<`(M7D-&3xvs@}!h?Sd%fTYPw1RxfUS zNa~pu#?f&W0z>u|Llg=vclN=hez@fiLF613#-?y*H%34Y=QDp=V+z7?p*LVqa)J{B zr&^qxk2H!;Tzm<>J(~}?+knqO-VRVj!j@ILfcsvxhAl6vODLfZ18f5oJm|ME1TfYn z%<}!tIeyg?RluXgwyFxK;t_UwSnPJ#QGW=80P6D+U4z~)g|3;M*1d>Eyb4|n_pUj@ zd+z#(Ij^wr9I)Sx&q1LO90m8TC!Yb4Pk;6DWjsSP4kwZX8%M#cf0{u< zAiIF5juY4fg`ZQ}j%U`sf227=nbSi#&hvY~*T>}(HtlKY<#nEHL*Ln+IwlXha$y-H zV4sx1y;?nz&0Zg>xs_;$F_2C6f_Xa@iCtxBk2eSJaQ&s zA&Ipuy=q|Y4$z4R6fo|)4MjnTd-O2CmlaZ%&>iRqjEF?){s7n6O_WzU4-Q^a>6M5J z7cV}mgUj{Xb*P11#ZzOzlL*s?pYIpile^Qk6np0p@vuQ?`s!nC`O0;DCnu4IAIL!f z2TDC(`Cm?9sf!o}iD}DsuJ>*Wz3htx^Wu2ZxrZk6tpl(M4=K=TX%lKzU0}s)7|1=$ykEQ_uv0x~~@rGLvNl?yJ_x zH(_vmXMkN~{SPWhNJtz{hxQ6S+?91{*-{P7TMI|C%aYIR0AXT6Ld%_Wfe~q6r3G?t z#(8s(EAvWtF)TVp2!`tss8{UlN^Xp0dj5cZE7-9k>P8pqlMF_95;fPvU< z2kn^|B;=8T%bqVdf=l5JxVM3BhhiBhQ%IYM0WsdkVfrMnQCtwMeC60*40RTW3kWDa zs6l8}VaM6oTQdFUEFnnTm2i)%hXh?gbJg6&_}X;IJ?LZ1vmfKget>rp+hmJv<^oX6I!*hU&>USxF2?nP|Bou z#Ku(+DwgJT+k1qXMQ*q4XE&kJXsbL&nm0`4BcsE={V9a-qwQ?&6A6TJ=KdG+|Guby zJgJ;hjR(2N?*_15|JlqI(O{!_fLP&{*aj2a_?eJyUShrgvIxEaoHgH#wtHkzL, && || !, = += -=, etc.). -- An `Expression` is a combination of operators, constants and variables that evaluate to a value. -- A `function` is a reusable block of code that performs a specific task. - ---- -## 1. Initialization -C++ provides several ways to initialize objects. Each form has different semantics and use cases. - -### 1.1. Default Initialization -```cpp -int a; -T object; -new T; -``` - -Performed when an object is created **without any initializer**. - - **Built-in types:** uninitialized - - **Class types:** default constructor is called - -
- -### 1.2. Value Initialization -```cpp -int a{}; - -T(); -new T(); -T object{}; -T{}; -new T{}; - -/// @brief Also used in constructors -Class::Class() : member() {} -Class::Class() : member{} {} -``` - -Performed when an object is created with an **empty initializer**. - - **Built-in types**: zero-initialized - - **Class types**: default constructor is called - -
- -### 1.3 Direct Initialization -```cpp -T object(arg); -T object(arg1, arg2); - -T object{arg}; // since C++11 -new T(args...); -static_cast(other); - -/// @brief Used in constructors and lambdas: -Class::Class() : member(args...) {} -[arg]() {}; -``` - -Initializes an object using **explicit constructor arguments**. - -
- -### 1.4 Copy Initialization -```cpp -T object = other; -f(other); -return other; -throw object; -catch (T object); - -/// @brief Also used for arrays -T array[N] = { /* values */ }; -``` -Initializes an object **from another object or expression**. - -### 1.5 List Initialization (since C++11) -```cpp -/// @brief Direct List Initialization -T object{arg1, arg2}; -new T{arg1, arg2}; - -Class::Class() : member{arg1, arg2} {} - -/// @brief Copy List Initialization -T object = {arg1, arg2}; -return {arg1, arg2}; -function({arg1, arg2}); - - -/// @brief Designated Initializers (since C++20) -T object{ .des1 = arg1, .des2 = arg2 }; -T object = { .des1 = arg1, .des2 = arg2 }; -``` - -Initializes objects using **brace-enclosed initializer lists { }**. - -
- -### 1.6 Aggregate Initialization -```cpp -T object = {arg1, arg2}; -T object{arg1, arg2}; // since C++11 - -/// @brief Designated initializers for aggregates (since C++20) -T object = { .des1 = arg1, .des2 = arg2 }; -T object{ .des1 = arg1, .des2 = arg2 }; -``` -Initializes **aggregate types** (no user-defined constructors). - ---- -## 2. Functions and Files -### 2.1. Function -```cpp - -returnType functionName(); ///< Forward Declaration - -/// @brief Function Definition -returnType functionName(){ - - -} -``` - -- A `forward declaration` allows us to tell the compiler about the existence of an identifier before actually defining the identifier. - -
- -### 2.2. Namespace -```cpp -namespace nested_config{ - namespace config{ - int value = 1; - } -} - -using namespace cfg = nested_config::config; - -void f(){ - std::cout << cfg::value; -} -``` -- `namespace` is a way to group names (variables, functions, classes, ...) together and avoid name conflicts. It guarantees that all identifiers within the namespace are unique -- `using namespace`: this is a using-directive that allows us to access names in the std namespace with no namespace prefix -- The `scope resolution operator (::)` used to access namespace member -- Can create `namespace aliases`, which allow us to temporarily shorten a long sequence of namespaces into something shorter. -- namespaces can be nested inside other namespaces. - -
- -### 2.3. Preprocessor -The `preprocessor` is a process that runs on the code before it is compiled. -```cpp -#include // insert file contents -#define NAME "Alex" // replace NAME -> "Alex" - -#ifdef NAME_DEFINED // only compile if defined -std::cout << NAME; -#endif -``` - -
- -### 2.3. Header Files -```cpp -#include // search system only -#include "my_header.h" // search local first, then system - -/// @brief Add include directories with -I -// g++ -o main -I./source/includes -I/home/abc/moreHeaders main.cpp -``` - -`Header files` are files designed to propagate declarations to code files. -- `Header guards` prevent the contents of a header from being included more than once into a given code file. -- For cross-platform library code, `#ifndef` is safest. -- For modern projects, `#pragma once` is simpler and safe. - ---- -## 3. Fundamental Data Types -Memory can only store bits. `Data type` help compiler and CPU take care of encoding the value into the sequence of bits. - - Fundamental Data Types - - Compound Data Types - -### 3.1 Primitive Type -| Types | Category | Meaning | Example | -| ------------------------------------------------------------------ | -------------------- | ------------------------------------------------ | ------- | -| float, double, long double | Floating Point | a number with a fractional part | 3.14159 | -| bool | Integral (Boolean) | true or false | true | -| char, wchar_t, char8_t (C++20), char16_t (C++11), char32_t (C++11) | Integral (Character) | a single character of text | 'c' | -| short int, int, long int, long long int (C++11) | Integral (Integer) | positive and negative whole numbers, including 0 | 64 | -| std::nullptr_t (C++11) | Null Pointer | a null pointer | nullptr | -| void | Void | no type | n/a | - -- `sizeof` used to get the size of a type in bytes. (pointer has 4 or 8 bytes based on the arch) -- `signed integers` can hold both positive and negative numbers (and 0). -- `unsigned integers` can only hold non-negative whole numbers. -- `fixed-width integers` are the set of integer types that are guaranteed to be the same size on any architecture **`#include `** - - `fast integers`: guarantee at least # bits, but pick the type that the CPU can process fastest (even if it uses more memory). - - `least integers`: guarantee at least # bits, but pick the type that uses the least memory (even if it’s slower). -- `size_t` vs `std::size_t` is an unsigned integral type that is used to represent the size or length of objects. (, ) -- `scientific notation e/E` used to present the times 10 to the power of the equation. e.g. **(e.g. 5.9722 x 10²⁴ -> 5.9722e24)** -- `Inf` represents infinity. Inf is signed, and can be positive (+Inf) or negative (-Inf). (5/0) -- `NaN` stands for “Not a Number”. (mathematically invalid) - -
- -### 3.2. Chars -- A `char` variable are interpreted as an `ASCII character`. -- `'t'`: Text between single quotes is treated as a char literal, which represents a single character. -- `"text"`: Text between double quotes (e.g. “Hello, world!”) is treated as a C-style string literal, which can contain multiple characters. -- **Escape sequences:** - | Name | Symbol | Meaning | - | --------------- | ------------ | ---------------------------------------------- | - | Alert | `\a` | Makes an alert, such as a beep | - | Backspace | `\b` | Moves the cursor back one space | - | Formfeed | `\f` | Moves the cursor to next logical page | - | Newline | `\n` | Moves cursor to next line | - | Carriage return | `\r` | Moves cursor to beginning of line | - | Horizontal tab | `\t` | Prints a horizontal tab | - | Vertical tab | `\v` | Prints a vertical tab | - | Single quote | `\'` | Prints a single quote | - | Double quote | `\"` | Prints a double quote | - | Backslash | `\\` | Prints a backslash | - | Question mark | `\?` | Prints a question mark *(no longer relevant)* | - | Octal number | `\{number}` | Translates into char represented by octal | - | Hex number | `\x{number}` | Translates into char represented by hex number | - ---- -## 4. Constant -- A `constant` is a value that is not be changed during the program’s execution. There are two types of constants: - - **Named constants**: are constant values that are associated with an identifier. - - Constant variables - - Macros with substitution text - - Enumerated constant - - **Literal** are constant values that are not associated with an identifier.Literals are values that are inserted directly into the code. - -
- -### 4.1. Named constants -```cpp -const double gravity = 9.8; ///< Const variable - -#define MY_NAME "Phong" ///< Object-like macros with substitution text - -enum Color { - RED, // Assigned 0 - GREEN, // Assigned 1 - BLUE = 5, // Manually assigned 5 - YELLOW // Assigned 6 (5 + 1) -};///< Enumerated constant -``` - -### 4.2. Literals - -```cpp -return 5; ///< 5 is an integer literal -> type: int -bool myNameIsAlex { true }; ///< true is a boolean literal -> type: bool -double d { 3.4 }; ///< 3.4 is a double literal -> type: double -cout << "Hello, world!"; ///< "Hello, world!" is a C-style string literal -> type: const char[14] -cout << 5.0 << '\n'; ///< 5.0 (no suffix) is type double (by default) -cout << 5.0f << '\n'; ///< 5.0f is type float -``` - -- `Type of a literal` is deduced from the literal's value. -- `Literal suffixes` used to explicitly declare the type for a literal. - -
- -### 4.3. Numeral systems (decimal, binary, hexadecimal, and octal) -- Numeral system literals: - - Decimal (no prefix, 42) - - Binary (0b101010) `b` - - Hexadecimal (0x2A) `x` - - Octal (052) — all represent the same value. -- Can change the output format via use of the `std::dec, std::oct, and std::hex` I/O manipulators: -- Can define a `std::bitset` variable and tell `std::bitset` how many bits we want to store. -```cpp - int bin{}; // assume 16-bit int - bin = 0x0001; // assign binary 0000 0000 0000 0001 to the variable - bin = 0b1; // assign binary 0000 0000 0000 0001 to the variable - bin = 0b11; // assign binary 0000 0000 0000 0011 to the variable - - cout << std::bitset<4>{ 0b1010 } << '\n'; // create a temporary std::bitset and print it - - // C++14: quotation mark (‘) as a digit separator - int bin { 0b1011'0010 }; // assign binary 1011 0010 to the variable - long value { 2'132'673'462 }; // much easier to read than 2132673462 -``` - -
- -### 4.4. Constant Expression -- `Constant expressions` is an expressions whose values can be fully determined at **compile time**. -- `constexpr` is used to declare compile-time constants -- Benefits: - - Safer code - - Optimizations - - Compile-time evaluation - -- `constexpr` function is is a function that is allowed to be called in a constant expression, can be evaluated at compile time or runtime. -- `consteval` function is a function that must evaluate at compile-time. - -```cpp -constexpr int square(int x) { - return x * x; -} - -consteval int cube(int x) { - return x * x * x; -} - -constexpr int a = square(5); // compile-time -int b = square(5); // runtime allowed - -constexpr int c = cube(5); // OK -// int d = cube(5); // Error if not compile-time -``` - ---- -## 5. Operators & Bit Manipulation -### 5.1. Operators -- Refer : https://www.learncpp.com/cpp-tutorial/operator-precedence-and-associativity/ -- `Increment/decrement`: - - `++x`: increment x, then return x - - `x++`: copy x, then increment x, return the copy -- `Comma`: - - `(x, y)`: Evaluate x then y, returns value of y - - avoid use this - -### 5.2. Bit manipulation. -- To define a set of bit flags, use `uint8/16/32`... or `std::bitset` -- Refers: https://www.learncpp.com/cpp-tutorial/bit-flags-and-bit-manipulation-via-stdbitset/ - ---- -## 6. Control Flows -### 6.1. Constexpr if statement (C++17) -- Condition will be evaluated at runtime. -- e.g. -```cpp -int main() -{ - constexpr double gravity{ 9.8 }; - - if constexpr (gravity == 9.8) // now using constexpr if - std::cout << "Gravity is normal.\n"; - else - std::cout << "We are not on Earth.\n"; - - return 0; -} -``` - -
- -### 6.2. Switch fallthrough and scoping -- The `[[fallthrough]]` attribute modifies a null statement to indicate that fallthrough is intentional (and no warnings should be triggered). -- Initialization is not allowed before case labels because control flow in a switch may jump over the initializer, leaving the variable uninitialized. -- Declarations without an initializer are allowed before case labels because they only reserve space for the variable in the function’s stack frame (decided at compile time). No runtime initialization code is generated, so nothing can be “skipped” by jumping to a case. -- e.g. -```cpp -int main() { - int x = 2; - - switch (x) { - int a; // allowed (no initializer, just reserves space) - // int b{5}; // not allowed (initializer may be skipped) - - case 1: - a = 10; // safe: 'a' exists, we assign here - std::cout << "Case 1, a = " << a << '\n'; - [[fallthrough]]; // intentional fallthrough to case 2 - - case 2: - a = 20; // reassign - std::cout << "Case 2, a = " << a << '\n'; - break; - - default: - std::cout << "Default case\n"; - break; - } - - return 0; -} -``` - -
- -### 6.3. Halts -- Halts allow us to terminate our program.Only use a halt if there is no safe or reasonable way to return normally from the main function. If you haven’t disabled exceptions, prefer using exceptions for handling errors safely. -- `std::exit` is called implicitly when main() returns, it does not clean up local variables in the current function or up the call stack. -- `std::abort()` function causes your program to terminate abnormally. Abnormal termination means the program had some kind of unusual runtime error and the program couldn’t continue to run. -- `std::terminate()` function is typically used in conjunction with exceptions . By default, it calls `std::abort()` -- e.g. -```cpp -#include -#include // for std::exit, std::abort -#include // for std::terminate - -void cleanup() { - std::cout << "Cleaning up...\n"; -} - -void riskyFunction(bool fatalError) { - if (fatalError) { - std::cout << "Fatal error occurred!\n"; - - // std::abort: abnormal termination, no cleanup - std::abort(); - - // Or: std::terminate(); // usually called when exception handling fails - } -} - -int main() { - cleanup(); // local function call - - // Example 1: return normally from main - std::cout << "Program running normally...\n"; - - // Example 2: using std::exit (implicit when main returns) - if (false) { - std::cout << "Exiting via std::exit...\n"; - std::exit(0); // does not call destructors of locals in main() - } - - // Example 3: risky code that might abort/terminate - riskyFunction(true); - - // Example 4: normal end of main calls std::exit implicitly - std::cout << "Main returns normally.\n"; - return 0; // std::exit(0) is called implicitly here -} -``` \ No newline at end of file diff --git a/src/core/concurrency/README.md b/src/core/concurrency/README.md deleted file mode 100644 index 8237806..0000000 --- a/src/core/concurrency/README.md +++ /dev/null @@ -1,237 +0,0 @@ -## 1. Concurrency -- **Concurrency** `refers to the ability` `to proccess` `multiple tasks` `at the same time.` -`On a single core`, it uses `context-switching`, `on multi-core systems`, it can run in parallel. -- It's `used to improve` the `program performance` and `response time`. -- In C/C++, we can archive concurrency by using `threads`. - -(`` is a C++ header that provide `a collection of types and functions` to work with time.) - ---- -## 2. Thread -- Threads are `the basic unit of` multitasking. -- There are many errors and risks associated with concurrency, including: - - `Deadlocks`: `refers to the situation where` two or more threads are blocked, `waiting for each other indefinitely`. - - `Race condition`: `refers to the situation where` two or more threads access `shared data` concurrently, leading to the `undefined behavior`. - - `Starvation`: `refer to the situation where` a thread `is unable to gain` regular access to the shared resources. -=> We can avoid these problems by `proper synchronization` between the threads. -- Use threads if we need to run long-lived and complex tasks. - -### 2.2. Thead Synchronization -- The synchronization can be done by using the following components: - - `Mutex/Lock`: `` they are used to protect the shared resouces, ensure that only one thread can access `the critical sections` at a time. - - `Semaphore`: - - `Futures and Promises`: ``, `` are used for the asynchronous task execution. - - `Condition variable`: `` -### 2.3. Thread Management -- `thread`: an `OS thread` `managed by` the kernel. -- Each `thread` has it own `call stack`, but all `threads` share the **heap**. -- `thread object`: refers to a C++ instance `that associated with` an `active thread` of execution in hardware level. -- `std::thread(callable)`: request the kernel OS to create a thread. -- `std::this_thread`: refer to the current thread -- `join`: blocks the current thread until the thread that identified by *this (a.ka. object thread) finished its execution. Note that if the exception -is throw before `join`, `std::terminate` might be called, and will kill the entire program process, not an invidual thread. -- `detach`: separates the `thread of the execution` from the `thread object`, allowing the execution to continue running. -- `yield`: give priority to other threads, pause its execution -- Use `return` to kill a thread. -### 2.4. Sharing Data -- `Global/Static Variable`: can be accessed by all threads. -- `Pass By Reference`: we need to explicitly wrap the args in `std::ref` to pass by reference and is the only way to properly get data out of a thread -- `thread_local` to create a static variable per thread. - -### 2.5. Atomic -- An atomic type is a type that implements atomic operations. It's used to guarantee no race conditions will occur. -- e.g. -`std::atomic` - `std::atomic_bool` -- e.g. -```cpp -#include -#include -#include -#include - -std::atomic_int acnt; -int cnt; - -void f() -{ - for (auto n{10000}; n; --n) - { - ++acnt; - ++cnt; - // Note: for this example, relaxed memory order is sufficient, - // e.g. acnt.fetch_add(1, std::memory_order_relaxed); - } -} - -int main() -{ - { - std::vector pool; - for (int n = 0; n < 10; ++n) - pool.emplace_back(f); - } - - std::cout << "The atomic counter is " << acnt << '\n' - << "The non-atomic counter is " << cnt << '\n'; -} -``` - -### 2.6. Mutex/Locks -- Mutexs are mutual exclusion objects, are owned by the thread that takes it. -- e.g. -```cpp -#include - -// Create your mutex here -std::mutex my_mutex; - -thread_function() -{ - my_mutex.lock(); // Acquire lock - // Do some non-thread safe stuff... - my_mutex.unlock(); // Release lock -} -``` - -- There are serveral types of mutex, including: - - `mutex` - - `timed_mutex` - - `recursive_mutex` - - `recursive_timed_mutex` - - `shared_timed_mutex` - -- **Lock Guard Type** is a wrapper mutex that provides a convinient RAII-style mechanism. -- They are several `lock guard types`, including: - - `std::lock_guard`: basic RAII lock for a single mutex. Locks immediately on construction, unlocks on destruction. - - `std::scoped_lock`: RAII lock for multiple mutexes - - `std::unique_lock`: Flexible RAII lock for a single mutex. Supports deferred/manual locking, unlocking, and use with condition variables, has unlock() / lock() - - `shared_lock`: RAII lock for shared access (readers) on a std::shared_mutex. Allows multiple concurrent readers. - -### 2.7. Condition Variable for event handling - -- `std::condition_variable` is a synchronization primitive used with a `std::mutex` to block one or more threads until another thread both modifies a `shared variable` (the condition) and `notifies` the `std::condition_variable`. -- `wait` will releases the lock and blocks the thread until the condition is fullfilled. -- e.g. -```cpp -#include -#include -#include -#include -#include - -std::mutex m; -std::condition_variable cv; -std::string data; -bool ready = false; -bool processed = false; - -void worker_thread() -{ - // 1. wait until main() sends data - std::unique_lock lk(m); - cv.wait(lk, []{ return ready; }); - - // after the wait, we own the lock - std::cout << "Worker thread is processing data\n"; - data += " after processing"; - - // send data back to main() - processed = true; - std::cout << "Worker thread signals data processing completed\n"; - - // manual unlocking is done before notifying, to avoid waking up - // the waiting thread only to block again (see notify_one for details) - lk.unlock(); - cv.notify_one(); -} - -int main() -{ - std::thread worker(worker_thread); - - data = "Example data"; - // send data to the worker thread - { - std::lock_guard lk(m); - ready = true; - std::cout << "main() signals data ready for processing\n"; - } - cv.notify_one(); - - // wait for the worker - { - std::unique_lock lk(m); - cv.wait(lk, []{ return processed; }); - } - std::cout << "Back in main(), data = " << data << '\n'; - - worker.join(); -} - -Output: -main() signals data ready for processing -Worker thread is processing data -Worker thread signals data processing completed -Back in main(), data = Example data after processing -``` - ---- -## 3. Task -- A `task` is a unit of asynchronous work that can be scheduled for execution. -- It is a higher-level abstraction than a thread. -- `It's generally considered` faster to work with tasks `as opposed to` threads, because the runtime can reuse threads and manage scheduling more efficiently. -- We use `task` if we want fairly simple code and don't care for managing threads, and are running shorts tasks. - -### 3.1. Promises and Futures -- `std::future` is a class template that stores a value that will be assigned in the future, and provide a way to access that value. - - It will also block if its value is accessed before the value is assigned. - - `Futures` are the objects that are returned by async operations (`std::async, std::promise, std::packaged_task`) -- `std::shared_future`: works the same way as `std::future`, except it is copytable, so multiple threads are allowed to wait for the same shared state. -- `std::promise` provides a way to store a value or an exception that will be retrieved asynchronously via a `std::future`. - - It is commonly used to pass results between threads. - - It creates a `std::future` using `get_future()`. - - The `std::promise` and the `std::future` share a common shared state. - - The `std::promise` sets the value of the shared state using `set_value()`. - - The associated `std::future` retrieves the value using `get()`. - - -### 3.2. Async -- `Async` is a function template allows we to spawn threads to do work async, then collect the results from them via the `future` mechanism. -- A call to `std::async` returns a `std::future` object. -- The future can later be used to retrieve the result of the asynchronous computation. - ```cpp - auto future = std::async(some_function, arg_1, arg_2); - ``` -- `std::async` may run the function in a `new thread` or `defer execution` until the result is requested. - - `std::launch::async`: launch in a separated thread - - `std::launch::deferred`: only be called on `get()` - - default: defer to system - ```cpp - auto future = std::async(std::launch::async,some_function, arg_1, arg_2); - ``` -![future](../../../docs/image/future_promis.png) -![future_flow](../../../docs/image/future_promis_flow.png) -- e.g. -```cpp -// Pass in function pointer -auto future = std::async(std::launch::async, some_function, arg_1, arg_2); - -// Pass in function reference -auto future = std::async(std::launch::async, &some_function, arg_1, arg_2); - -// Pass in function object -struct SomeFunctionObject -{ - void operator() (int arg_1){} -}; -auto future = std::async(std::launch::async, SomeFunctionObject(), arg_1); - -// Lambda function -auto future = std::async(std::launch::async, [](){}); -``` - -## 4. Date and time library -- The `chrono` (since c++11) library defines several main types as well as utility functions and common typedefs: - - clocks - - time points - - durations - - calender/timezone (c++ 20); \ No newline at end of file diff --git a/src/core/exception/README.md b/src/core/exception/README.md deleted file mode 100644 index 353894a..0000000 --- a/src/core/exception/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# 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. - -**- 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/function/README.md b/src/core/function/README.md deleted file mode 100644 index 62eaba6..0000000 --- a/src/core/function/README.md +++ /dev/null @@ -1,238 +0,0 @@ - ---- -# Functions -Functions are self-contained blocks of code designed to perform specific tasks. They promote code reusability, modularity, and abstraction. -Functions can participate in polymorphism through: -- **Compile-time polymorphism (Static Polymorphism)** - - Function overloading - - Operator overloading - - Function templates -- **Runtime polymorphism** - - Virtual functions - ---- -## 1. Function Overloading -- `function overloading` allows us to create multiple functions with the same name, so long as each identically named function has different parameter types/numbers. Return types are not considered for -- `function delete` using `delete` keyword. delete means "I forbid this", not "this doesn’t exist". -- `default-arguments`: is a default value provided for a function parameter. Parameters with default arguments must always be the rightmost parameters, and they are not used to differentiate functions when resolving overloaded functions. -```cpp -void printInt(int x) -{ - std::cout << x << '\n'; -} - -void printIntOrDefault(int x, int y = 2) -{ - std::cout << x << ", " << y << '\n'; -} - -template -void printInt(T) = delete; - -int main() -{ - printInt(97); // okay - - // printInt('a'); // compile error - // printInt(true); // compile error - - printIntOrDefault(5); // prints: 5, 2 - printIntOrDefault(5, 10); // prints: 5, 10 - - return 0; -} -``` - ---- -## 2. Operator Overloading - -- **Operator overloading** allows C++ operators to be customized for user-defined types. -- An overloaded operator is implemented as a special function called an **operator function**. - -- Operator Function Names: - ```cpp - operator op - - operator new - operator new[] - operator delete - operator delete[] - - operator co_await // C++20 - ``` - -- Operator Syntax: - | Expression | Member Function | Non-member Function | Example | - | ---------- | -------------------- | ------------------- | --------------------------------------------------- | - | `@a` | `a.operator@()` | `operator@(a)` | `!a` calls `a.operator!()` | - | `a@b` | `a.operator@(b)` | `operator@(a, b)` | `std::cout << 42` calls `std::cout.operator<<(42)` | - | `a=b` | `a.operator=(b)` | N/A | `s = "abc"` calls `s.operator=("abc")` | - | `a(b...)` | `a.operator()(b...)` | N/A | `r(1)` calls `r.operator()(1)` | - | `a[b]` | `a.operator[](b)` | N/A | `m[1]` calls `m.operator[](1)` | - | `a->` | `a.operator->()` | N/A | `p->do()` calls `p.operator->()` | - | `a@` | `a.operator@(0)` | `operator@(a, 0)` | `i++` calls `i.operator++(0)` | - -- Restrictions: - The following operators **cannot be overloaded**: - ```cpp - :: // scope resolution - . // member access - .* // member access through pointer-to-member - ?: // conditional operator - ``` - - New operators cannot be created. - - Operators such as `**`, `<>`, or `&|` are invalid. - - At least one operand must be a user-defined type. - - Overloading does not change an operator's precedence, associativity, or number of operands. - - -#### Assignment Operator (`=`) -- Return the lhs by reference -```cpp -// copy assignment -T& operator=(const T& other) -{ - // Guard self assignment - if (this == &other) - return *this; - - // - - return *this; -} - -// move assignment -T& operator=(T&& other) noexcept -{ - // Guard self assignment - if (this == &other) - return *this; // delete[]/size=0 would also be ok - - // - - return *this; -} -``` - -#### Stream Extraction and Insertion (`>>`, `<<`) -- Must be implemented as non-members cause that take a `std::istream&` or `std::ostream&` as the left hand argument `std::cout << a; std::cout.operator << (a)` -```cpp -std::ostream& operator<<(std::ostream& os, const T& obj) -{ - // write obj to stream - return os; -} - -std::istream& operator>>(std::istream& is, T& obj) -{ - // read obj from stream - if (/* T could not be constructed */) - is.setstate(std::ios::failbit); - return is; -} -``` - -#### Function Call Operator (`()`) - -#### Increment and Decrement (`++`, `--`) - -#### Binary Arithmetic Operators (`+`, `-`, `*`, `/`) - -#### Comparison Operators (`==`, `!=`, `<`, `>`, `<=`, `>=`) - -#### Array Subscript Operator (`[]`) - -#### Bitwise Operators (`&`, `|`, `^`, `~`, `<<`, `>>`) - -#### Boolean Negation Operator (`!`) - ---- -## 3. Lambda -- In C++11 and later, lambda is a convenient way of defining an anonymous function object right at the location where it's involked or passed as an argument to a function. - -- Syntax: - ```cpp - [=] () mutable throw() -> int - { - int n = x + y; - return n; - } - - ``` - - `[=]`: capture clause a.k.a lambda introducer - - `()`: *(Optional)* pararam list a.k.a lambda declarator - - `mutable`: *(Optional)* - - `throw()`: *(Optional)* - - `-> int`: *(Optional)* trailing-return-type - - `[](){ ... }` defines a lambda - - `[](){ ... }()` defines and immediately CALLS it - -### Capture Clause -- It uses to introduce new variables in its body, specifics which vars are captured, and whether the capture is `by value[=]` or `by reference [&]`. -- An empty capture clause `[]` indicates that the body accesses no vars in the enclosing scope. -- An identifier or `this` cannot appear more than once in a capture scope. -- Since C++14, we can introduce and initialize new vars in the capture scope. -- e.g. - ```cpp - int a{}; - int b{}; - - auto f = []{ // no capture - return 1; - } - - auto f0 = [a]{ // capture by value - return a+1; - } - - auto f1 = [&a]{ - return a+=1; // capture by reference (a = 1) - } - - auto f2 = [=]{ - return a + b; // all capture by value - } - - auto f3 = [&]{ - a+=1; - b+=1; - return a + b; // all capture by reference - } - - auto f4 = [int a{}]{ // no capture - return a; - } - ``` - ---- -## 4. Function Pointers -- A function pointer is a pointer variable that stores the address of a function with a specific return type and parameter list. -- Syntax: `return_type (*FuncPtr) (parameter type, ....);` -```cpp -// @brief Declaration -rtype (*FuncPtr) (atype..); - -// @brief Referencing: Assigning a function’s address to the function pointer. -FuncPtr = function_name; - -// @brief Dereferencing: Invoking the function using the pointer. The dereference operator * is optional during function calls. -FuncPtr(10, 20); // Preferred -(*FuncPtr)(10, 20); // Also valid -``` - ---- -## 5. **``** -- `std::function` is a general-purpose polymorphic function wrapper introduced in C++11. - - It can store and invoke any callable object: - - Functions - - Lambda expressions - - Functors (objects that overload `operator()`) - - Member functions (with binding) - - It provides a common interface for different callable types. - - Commonly used for callbacks, event handling, task dispatching, and functional-style programming. - - Improves code flexibility, reusability, and maintainability. - -- Syntax: `std::function name()` / `std::function< ret_t (args_t)> name = f;` / `std::function< ret_t (args_t)> name(f);` - - ---- \ No newline at end of file diff --git a/src/core/smart_pointer/README.md b/src/core/smart_pointer/README.md deleted file mode 100644 index c57d5da..0000000 --- a/src/core/smart_pointer/README.md +++ /dev/null @@ -1,164 +0,0 @@ -## 1. Smart Pointers -- The STL includes smart pointers, which are defined in the to help ensure that programs are free of memory and resource leaks. -- Raw pointers are only used in small code blocks where performance is critical and we can control the ownership stuff. -- e.g. -```cpp -void UseRawPointer() -{ - // Using a raw pointer -- not recommended. - Song* pSong = new Song(L"Nothing on You", L"Bruno Mars"); - - // Use pSong... - - // Delete - delete pSong; -} - -void UseSmartPointer() -{ - // Declare a smart pointer on stack and pass it the raw pointer. - unique_ptr song2(new Song(L"Nothing on You", L"Bruno Mars")); - - // Use song2... - wstring s = song2->duration_; - //... - -} // song2 is deleted automatically here. -``` - -- After being initialized, the smart pointer owns the raw pointer. -- Use the overloaded `->` and `*` operators to access the object. -- Use `get()` to access the raw pointer directly. -- There are some kinds of the smart pointer: - - `unique_ptr`: this is the default choice for POCO, **one owner** - - `shared_ptr`: **multiple owners**, the raw pointer deleted when all owners have gone out of scope or have otherwise given up ownership. - - `weak_ptr`: provides access to an object that is owned by one or more `shared_ptr`, but holds a **non-owning** reference to this object. - ---- -## 2. std::unique_ptr -- It can **only be moved** and cannot be passed by value, copied. -- e.g. -```cpp -unique_ptr SongFactory(const std::wstring& artist, const std::wstring& title) -{ - // Implicit move operation into the variable that stores the result. - return make_unique(artist, title); -} - -void MakeSongs() -{ - // Create a new unique_ptr with a new object. - auto song = make_unique(L"Mr. Children", L"Namonaki Uta"); - - // Use the unique_ptr. - vector titles = { song->title }; - - // Move raw pointer from one unique_ptr to another. - unique_ptr song2 = std::move(song); - - // Obtain unique_ptr from function that returns by value. - auto song3 = SongFactory(L"Michael Jackson", L"Beat It"); -} - -// Create a unique_ptr to an array of 5 integers. -auto p = make_unique(5); - -// Initialize the array. -for (int i = 0; i < 5; ++i) -{ - p[i] = i; - wcout << p[i] << endl; -} -``` - -## 3. std::shared_ptr -- It is designed for scenarios in which more than one owner needs to manage the lifetime of an object. -- It can be copied, passed by value in function arguments, and assigned to other `shared_ptr` instances. -- All the instances point to the same object, and share access to one "control block" that increments and decrements the reference count whenever a new shared_ptr is added, goes out of scope, or is reset. **When the reference count reaches zero, the control block deletes the memory resource and itself**. -- e.g. -```cpp -// Use make_shared function when possible. -auto sp1 = make_shared(L"The Beatles", L"Im Happy Just to Dance With You"); - -// Ok, but slightly less efficient. -// Note: Using new expression as constructor argument -// creates no named variable for other code to access. -shared_ptr sp2(new Song(L"Lady Gaga", L"Just Dance")); - -// When initialization must be separate from declaration, e.g. class members, -// initialize with nullptr to make your programming intent explicit. -shared_ptr sp5(nullptr); -//Equivalent to: shared_ptr sp5; -//... -sp5 = make_shared(L"Elton John", L"I'm Still Standing"); - -//Initialize with copy constructor. Increments ref count. -auto sp3(sp2); - -//Initialize via assignment. Increments ref count. -auto sp4 = sp2; - -//Initialize with nullptr. sp7 is empty. -shared_ptr sp7(nullptr); - -// Initialize with another shared_ptr. sp1 and sp2 -// swap pointers as well as ref counts. -sp1.swap(sp2); -``` - -## 4. std::weak_ptr -- It's used to to access the underlying object of a shared_ptr without causing the reference count to be incremented. -- If the memory has already been deleted, the weak_ptr's bool operator returns false. -- e.g. -> std::weak_ptr is a very good way to solve the dangling pointer problem. By just using raw pointers it is impossible to know if the referenced data has been deallocated or not. Instead, by letting a std::shared_ptr manage the data, and supplying std::weak_ptr to users of the data, the users can check validity of the data by calling expired() or lock(). -You could not do this with std::shared_ptr alone, because all std::shared_ptr instances share the ownership of the data which is not removed before all instances of std::shared_ptr are removed. Here is an example of how to check for dangling pointer using lock(): -```cpp -// Source - https://stackoverflow.com/a/21877073 -// Posted by sunefred, modified by community. See post 'Timeline' for change history -// Retrieved 2026-02-06, License - CC BY-SA 4.0 - -#include -#include - -int main() -{ - // OLD, problem with dangling pointer - // PROBLEM: ref will point to undefined data! - - int* ptr = new int(10); - int* ref = ptr; - delete ptr; - - // NEW - // SOLUTION: check expired() or lock() to determine if pointer is valid - - // empty definition - std::shared_ptr sptr; - - // takes ownership of pointer - sptr.reset(new int); - *sptr = 10; - - // get pointer to data without taking ownership - std::weak_ptr weak1 = sptr; - - // deletes managed object, acquires new pointer - sptr.reset(new int); - *sptr = 5; - - // get pointer to new data without taking ownership - std::weak_ptr weak2 = sptr; - - // weak1 is expired! - if(auto tmp = weak1.lock()) - std::cout << "weak1 value is " << *tmp << '\n'; - else - std::cout << "weak1 is expired\n"; - - // weak2 points to new data (5) - if(auto tmp = weak2.lock()) - std::cout << "weak2 value is " << *tmp << '\n'; - else - std::cout << "weak2 is expired\n"; -} -``` \ No newline at end of file diff --git a/src/core/string/README.md b/src/core/string/README.md deleted file mode 100644 index 3e6afef..0000000 --- a/src/core/string/README.md +++ /dev/null @@ -1,332 +0,0 @@ -# String - -## 1. C-Style String -A C-Style string is any **null-terminated byte string**, where this is a sequence of nonzero bytes followed by a byte with zero (0) value (the terminating null character). -- The terminating null character is represented as the character literal **'\0'**; -- The length of an NTBS is the number of elements that precede the terminating null character. An empty NTBS has a length of zero. -- The size of an NTBS is the size of the entire array, including the terminating null character. -- A single quotes `(')` are used to identify **character literals**. -- A double quotes `('')` are used to identify **string literals**. String literals are stored in your program image, usually in a read-only section (.data), - -
- -### 1.1. Create a String -```c -// *1. Ptr -char* strMessagePtr= "abc"; -// sizeof(strMessage) = 32 or 64 (ptr) -strMessagePtr[0] = 1; // error, ptr to const - -// *2. Arrays -char strMessage[] = "abc"; -// sizeof(strMessage ) = 4 -strMessage[1] = 'a'; // OK -``` -- For `strMessage`, the memory for the array is allocated on the stack at runtime. The compiler initializes it from the string literal. At runtime, the program memory copies the string literal into the array -- For `strMessagePtr`, only the address of the string literal is held on the stack, and there is no copying of string literal. - -
- -### 1.2. Characters -- Null: `\0`, `0x00`, `NULL` -- Carriage Return And New Line: `\r\n` -- Case switching: `'A' ^ ' '` & `'a' ^ ' '` -- Special: `\\`, -- **Escape sequences:** - | Name | Symbol | Meaning | - | --------------- | ------------ | ---------------------------------------------- | - | Alert | `\a` | Makes an alert, such as a beep | - | Backspace | `\b` | Moves the cursor back one space | - | Formfeed | `\f` | Moves the cursor to next logical page | - | Newline | `\n` | Moves cursor to next line | - | Carriage return | `\r` | Moves cursor to beginning of line | - | Horizontal tab | `\t` | Prints a horizontal tab | - | Vertical tab | `\v` | Prints a vertical tab | - | Single quote | `\'` | Prints a single quote | - | Double quote | `\"` | Prints a double quote | - | Backslash | `\\` | Prints a backslash | - | Question mark | `\?` | Prints a question mark *(no longer relevant)* | - | Octal number | `\{number}` | Translates into char represented by octal | - | Hex number | `\x{number}` | Translates into char represented by hex number | - -
- -### 1.3. C String Libraries -- Copying strings : `strcpy`, `strncpy` -- Concatenating strings: `strcat`, `strncat` -- Comparing strings: `strcmp`, `strncmp` -- Parsing strings: `strtok`, `strcspn` -- Length: `strlen` -- Examples: -```cpp -#include -#include - -int main() { - // ------------------------------- - // 1. Copying strings - // ------------------------------- - char src[] = "Hello"; - char dst[20]; - - strcpy(dst, src); // copy full string - // dst = "Hello" - - strncpy(dst, "World", 3); // copy only 3 chars - dst[3] = '\0'; // ensure null-termination - // dst = "Wor" - - // ------------------------------- - // 2. Concatenating strings - // ------------------------------- - char text[20] = "Hi"; - strcat(text, " there"); // append full string - // text = "Hi there" - - strncat(text, "!!!", 2); // append only 2 chars - // text = "Hi there!!" - - // ------------------------------- - // 3. Comparing strings - // ------------------------------- - int r1 = strcmp("abc", "abc"); // r1 = 0 (equal) - int r2 = strcmp("abc", "abd"); // r2 < 0 (abc < abd) - int r3 = strncmp("abcdef", "abcxyz", 3); // r3 = 0 (first 3 chars equal) - - // ------------------------------- - // 4. Parsing strings - // ------------------------------- - char line[] = "A,B,C"; - char* token = strtok(line, ","); // first token: "A" - while (token != NULL) { - printf("token: %s\n", token); - token = strtok(NULL, ","); - } - - // strcspn: find first occurrence of any chars in reject set - char sample[] = "hello123world"; - size_t pos = strcspn(sample, "0123456789"); - // pos = 5 (first digit is at index 5) - - // ------------------------------- - // 5. Length - // ------------------------------- - size_t len = strlen("abc"); // len = 3 - - return 0; -} -``` - -
- -### 1.4. String/Numbers Conversion -- Integer to String: `itoa()` (non-standard) -- String to Double: `atof()` -- String to Double (with error checking): `strtod()` -- String to Long (with base + error checking): `strtol()` -- e.g. -```c -#include -#include // atof, strtod, strtol -#include // itoa (non-standard on some compilers) - -int main() { - // ------------------------------- - // 1. Integer → String (itoa) - // ------------------------------- - char buf[32]; - itoa(1234, buf, 10); // convert integer to string in base 10 - // buf = "1234" - - itoa(255, buf, 16); // convert to hex - // buf = "ff" - - // ------------------------------- - // 2. String → Double (atof) - // ------------------------------- - double d1 = atof("3.14159"); - // d1 = 3.14159 - - double d2 = atof("12.5xyz"); - // d2 = 12.5 (atof stops at non-numeric chars) - - // ------------------------------- - // 3. String → Double (strtod) - // ------------------------------- - char* end; - double d3 = strtod("45.67abc", &end); - // d3 = 45.67 - // end -> "abc" - - // ------------------------------- - // 4. String → Long (strtol) - // ------------------------------- - long v1 = strtol("1234", NULL, 10); - // v1 = 1234 (decimal) - - long v2 = strtol("FF", NULL, 16); - // v2 = 255 (hex → decimal) - - char* end2; - long v3 = strtol("100xyz", &end2, 10); - // v3 = 100 - // end2 -> "xyz" - - return 0; -} -``` - -
- ---- -## 2. C++ String **** -Strings are objects that represent sequences of characters. - -### 2.1. Create a String -```cpp -std::string s = "hello"; ///< initialize from a string literal -std::string s2("hello"); ///< direct initialization from a string literal -std::string s3(5, 'a'); ///< create a string with 5 copies of 'a' -> "aaaaa" -``` - -### 2.2. Basic Properties -| Function | Description | -| ------------ | --------------------- | -| `s.size()` | number of characters | -| `s.length()` | same as size | -| `s.empty()` | check empty | -| `s.clear()` | remove all characters | - -### 2.3. Access Characters -```cpp -s[0] // no bounds check -s.at(0) // bounds check -s.front() // first char -s.back() // last char -``` -### 2.4. Modify String -```cpp -/// @brief append -s.append(" world"); -s += " world"; - -/// @brief insert -s.insert(5, "XXX"); - -/// @brief erase -s.erase(0,2); - -/// @brief replace -s.replace(0,5,"hi"); - -/// @brief remove `\n` -std::string s = "hello\nworld\n"; -auto new_end = std::remove(s.begin(), s.end(), '\n'); -s.erase(new_end) -// std::erase(s,'\n') -s.erase(std::remove(s.begin(), s.end(), '\n'), s.end()); -``` -### 2.5. Substring -```cpp -/// @brief std::string sub = s.substr(pos, len); , substr() does NOT modify original string -std::string s = "abcdef"; -s.substr(2,3); // "cde" -``` -### 2.6. Find / Search -```cpp -/// @brief find character -s.find('a'); - - -/// @brief find last -s.find('a'); - - -/// @brief find substring -size_t pos = s.find("abc"); -if (pos != std::string::npos) - std::cout << "found"; -``` -### 2.6. Compare Strings -```cpp -if (a == b) -if (a != b) -if (a < b) - -// 0 -> equal -// <0 -> smaller -// >0 -> larger -auto ret = a.compare(b); -``` -### 2.7. Start/End Checking -```cpp -/// @brief C++20 -s.starts_with("abc"); -s.ends_with("xyz"); - -/// @brief before c++ 20 -s.rfind("abc",0) == 0 -s.size() >= 3 && -s.compare(s.size()-3,3,"xyz") == 0 -``` -### 2.8. Convert String -```cpp -/// @brief string to int -int n = std::stoi(s); -double x = std::stod("3.14"); - -/// @brief int to string -std::string s = std::to_string(123); -``` - -### 2.9. String Parsing -```cpp -#include - -std::string line = "a,b,c"; -std::stringstream ss(line); -std::string item; - -while(std::getline(ss,item,',')) { - std::cout << item << std::endl; -} -``` - -### 2.10. Trim Whitespace -```cpp -s.erase(0, s.find_first_not_of(" \t\n\r")); -s.erase(s.find_last_not_of(" \t\n\r") + 1); -``` - -### 2.11. Convert Case -```cpp -#include - -std::transform(s.begin(), s.end(), s.begin(), ::tolower); -std::transform(s.begin(), s.end(), s.begin(), ::toupper); -``` - -### 2.12. String Formatting - -| Method | Standard | Pros | Cons | -|------------------|----------|--------------------------|------------------------------| -| `std::format` | C++20 | Clean, safe, Python-like | Needs newer compiler | -| `+` concatenation | C++98 | Simple | Hard to format numbers | -| `stringstream` | C++98 | Flexible streaming | Slow, verbose | -| `snprintf` | C | Very fast, classic | Unsafe if misused | - ---- -## 3. std::cout << , std::cin >> , std::getLine(std::cin >> std::ws, std::string string) -- `std::ws` tells `std::cin` to ignore leading whitespace(tab/enter/newline(s)) before extraction. -- `std::string::length` returns length of a string that does not included the null terminator character. -- `s` suffix is a `std::string` literally, no suffix is a C-style string literally. e.g. `std::cout << "goo\n"s` -> Initializing and copy a `std::string` is slow. That's inefficient - ---- -## 4. std::string_view (C++17) -`std::string_view` provides read-only access to an existing string (a C-style string literal, a std::string, or a char array) without making a copy. -- A std::string_view that is viewing a string that has been destroyed is sometimes called a dangling view. When a std::string is modified, all views into that std::string are invalidated, meaning those views are now invalid. Using an invalidated view (other than to revalidate it) will produce undefined behavior. - -- `sv` suffix is a `std::string_view` literally -- Modify a std::string is likely to invalidate all std::string_view that view into that. -- It may or may not be null-terminated. \ No newline at end of file From bb5caa69d3337742f0755522c112cb2a5446d9a7 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 21 Jun 2026 21:00:17 +0700 Subject: [PATCH 10/18] fix doc issue --- src/embedded/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/embedded/README.md b/src/embedded/README.md index e8fed9a..8cc4058 100644 --- a/src/embedded/README.md +++ b/src/embedded/README.md @@ -146,6 +146,7 @@ A microcontroller does not start executing from `main()` after power-up or reset +----------------------+ | Copy .data | | Flash --> SRAM | + +----------------------+ v +--------------------------------------------------+ | STM32 SRAM | From f4a6b9b40546ef507b32dd2b3df43d2ede967cee Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Mon, 22 Jun 2026 09:56:41 +0700 Subject: [PATCH 11/18] Update for initialization --- src/core/CMakeLists.txt | 2 +- src/core/basics/Initialization.cpp | 114 +++++++++++++++++++++++++ src/core/basics/InitializeVariable.cpp | 69 --------------- 3 files changed, 115 insertions(+), 70 deletions(-) create mode 100644 src/core/basics/Initialization.cpp delete mode 100644 src/core/basics/InitializeVariable.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2cd55ad..0da196b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -7,7 +7,7 @@ set(CORE_SOURCES # Basic C++ language features - ${CMAKE_CURRENT_SOURCE_DIR}/basics/InitializeVariable.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/basics/Initialization.cpp ${CMAKE_CURRENT_SOURCE_DIR}/basics/Operations.cpp ${CMAKE_CURRENT_SOURCE_DIR}/basics/TypeQualifier.cpp ${CMAKE_CURRENT_SOURCE_DIR}/basics/ControlFlow.cpp diff --git a/src/core/basics/Initialization.cpp b/src/core/basics/Initialization.cpp new file mode 100644 index 0000000..7e3b473 --- /dev/null +++ b/src/core/basics/Initialization.cpp @@ -0,0 +1,114 @@ +// cppcheck-suppress-file [unreadVariable, unusedVariable, functionStatic] + +#include "ExampleRegistry.h" +#include "Logger.h" + +/// @brief Dummy class +struct Dummy { + Dummy() { LOG("Default ctor"); } + explicit Dummy(int value) { LOG_S("Int ctor: " << value); } + Dummy(const Dummy&) { LOG("Copy ctor"); } +}; + +/// @brief Aggregate type +struct Aggregate { + int x; + int y; +}; + +/// @brief Default Initialization +void default_ini() { + int a; + LOG_S("a = " << a); + + Dummy object; + + auto* p1 = new int; + LOG_S("*p1 = " << *p1); + auto* p2 = new Dummy; + + delete p1; + delete p2; +} + +/// @brief Value Initialization +void value_ini() { + // int x();Dummy obj(); // Most Vexing Parse:function declaration + + int a = int(); + int b{}; + + LOG_S("a = " << a); + LOG_S("b = " << b); + + Dummy object1 = Dummy(); // value initialization x copy-initialization + Dummy object2{}; + + auto* p1 = new int(); + LOG_S("*p1 = " << *p1); + + auto* p2 = new Dummy(); + + delete p1; + delete p2; +} + +/// @brief Direct Initialization +void direct_ini() { + int a(42); + + Dummy object1(1); + Dummy object2(static_cast(2)); + + LOG_S("a = " << a); +} + +/// @brief Copy Initialization +void copy_ini() { + Dummy source{1}; + + Dummy object1 = source; + Dummy object2 = Dummy{2}; + + int value = 42; + + LOG_S("value = " << value); +} + +/// @brief List Initialization (since C++11) +void list_ini() { + Dummy object1{1}; // direct-list-init + Dummy object2 = {static_cast(2)}; // copy-list-init + + int values1[]{1, 2, 3}; + int values2[] = {4, 5, 6}; +} + +/// @brief Aggregate Initialization +void aggregate_ini() { + Aggregate a1 = {1, 2}; + Aggregate a2{3, 4}; + Aggregate a3{.x = 3, .y = 4}; + + LOG_S("a1 = {" << a1.x << ", " << a1.y << "}"); + LOG_S("a2 = {" << a2.x << ", " << a2.y << "}"); + LOG_S("a3 = {" << a3.x << ", " << a3.y << "}"); +} + +class Initialization : public IExample { + public: + std::string group() const override { return "core/basics"; } + std::string name() const override { return "Initialization"; } + std::string description() const override { return "Initialization Examples"; } + + void execute() override { + default_ini(); + value_ini(); + direct_ini(); + copy_ini(); + list_ini(); + aggregate_ini(); + } +}; + +REGISTER_EXAMPLE(Initialization); \ No newline at end of file diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp deleted file mode 100644 index 57c5163..0000000 --- a/src/core/basics/InitializeVariable.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// cppcheck-suppress-file [unreadVariable, unusedVariable, functionStatic] - -#include "Logger.h" -#include "ExampleRegistry.h" - -void initialize_variable(); - -class InitializeVariable : public IExample { - public: - std::string group() const override { return "core/basics"; } - std::string name() const override { return "InitializeVariable"; } - std::string description() const override { return "InitializeVariable"; } - - void execute() override { initialize_variable(); } -}; - -REGISTER_EXAMPLE(InitializeVariable); - -struct Foo { - Foo() { LOG("Default constructor/ default init"); } - - // Foo(int) - explicit Foo(int) { - LOG( "Constructor called with int / copy init"); - } - - Foo(const Foo& other) { - other.dump(); - LOG( "Copy constructor called"); - } - - void dump() const {} -}; - -void initialize_variable() { - LOG( "\n--- Variable Initialization Examples ---"); - // * 1) Default-initialization - int init_default_var; - Foo init_default_obj; - - auto* c = new unsigned char; - *c = 0xF; // actual init at this point for c - delete c; - - // * 2) Value-initialization - int init_value_var1(); - int init_value_var2{}; - - // * 3) direct-init: Type var(value); - 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. - 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. - Foo brace_init{3}; - // Foo braceInit2{3.3}; // ERORR => Prefer this way - int ar[] = {1, 2, 3}; // aggregate init - int ar2[]{1, 2, 3}; -} \ No newline at end of file From b6ddcee98e8c5b1458e4d49ebee29452ea9e14ec Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Wed, 24 Jun 2026 13:19:59 +0700 Subject: [PATCH 12/18] Update script to ignore static check embedded stuffs --- scripts/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/run.sh b/scripts/run.sh index a15e535..6383704 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -45,7 +45,8 @@ cppcheck \ --inline-suppr \ --quiet \ --error-exitcode=1 \ - ./src ./include + ./src ./include \ + -isrc/embedded/ echo "[OK] Static analysis passed" From 98a3fdf5acf428b840c48b7d8ff6422cb4ad832c Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Wed, 24 Jun 2026 13:20:15 +0700 Subject: [PATCH 13/18] refactor --- src/core/basics/Initialization.cpp | 2 +- src/core/utils/Variadic.cpp | 29 ++++++++++------------------- src/embedded/README.md | 1 - 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/core/basics/Initialization.cpp b/src/core/basics/Initialization.cpp index 7e3b473..853af7e 100644 --- a/src/core/basics/Initialization.cpp +++ b/src/core/basics/Initialization.cpp @@ -1,4 +1,4 @@ -// cppcheck-suppress-file [unreadVariable, unusedVariable, functionStatic] +// cppcheck-suppress-file [unreadVariable, unusedVariable, uninitdata, uninitvar, unassignedVariable] #include "ExampleRegistry.h" #include "Logger.h" diff --git a/src/core/utils/Variadic.cpp b/src/core/utils/Variadic.cpp index 57a0519..3f02483 100644 --- a/src/core/utils/Variadic.cpp +++ b/src/core/utils/Variadic.cpp @@ -5,14 +5,12 @@ #include "Logger.h" namespace c_variadic_style { -/** - * @brief Simple C-style variadic function example. - * - * The format string controls how arguments are read: - * d -> int - * c -> char - * f -> double - */ + +/// @brief Simple C-style variadic function +/// The format string controls how arguments are read: +/// d -> int +/// c -> char +/// f -> double void simple_printf(const char* fmt, ...) { // Holds all unnamed arguments va_list args; @@ -53,14 +51,11 @@ void run() { } // namespace c_variadic_style namespace modern_variadic_style { -/** - * @brief Base case for recursion. - */ + +/// @brief Base case for recursion inline void simple_printf(const char* /*fmt*/) {} -/** - * @brief Print one argument based on format specifier. - */ +/// @brief Print one argument based on format specifier template void print_arg(char fmt, const T& value) { switch (fmt) { @@ -81,9 +76,7 @@ void print_arg(char fmt, const T& value) { } } -/** - * @brief Recursive variadic template implementation. - */ +/// @brief Recursive variadic template implementation template void simple_printf(const char* fmt, T value, Args... args) { if (*fmt == '\0') { @@ -107,9 +100,7 @@ void run() { class Variadic : public IExample { public: std::string group() const override { return "core/utils"; } - std::string name() const override { return "Variadic"; } - std::string description() const override { return "Examples for C-style variadic arguments"; } diff --git a/src/embedded/README.md b/src/embedded/README.md index 8cc4058..917b832 100644 --- a/src/embedded/README.md +++ b/src/embedded/README.md @@ -59,7 +59,6 @@ $ arm-none-eabi-objcopy # ELF to BIN converter $ arm-none-eabi-gdb # Debugger ``` -`$ qemu-system-arm -M stm32vldiscovery -kernel firmware.bin` ### 1.4. Linker Script **Linker Script** is a configuration file that tells the linker how to place the program into the mcu memory. - Define the memory layout: Flash, RAM, Stack, Heap From 864f46b415809cf978f0d6029290403ec5ea85c8 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 23 Jul 2026 14:26:27 +0700 Subject: [PATCH 14/18] Update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d2d49df..e84cd09 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ coverage_gcovr coverage_lcov !.vscode/launch.json !.vscode/tasks.json -.cache \ No newline at end of file +.cache +__pycache__/ \ No newline at end of file From 061f35059c7da036c49c6bb078e6e1b2a5eae778 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Jul 2026 20:36:00 +0700 Subject: [PATCH 15/18] Update for Abstract factory --- src/dp/creational/AbstractFactory.cpp | 100 +++++++++++-------------- src/dp/creational/FactoryMethod.cpp | 101 +++++++++----------------- 2 files changed, 74 insertions(+), 127 deletions(-) diff --git a/src/dp/creational/AbstractFactory.cpp b/src/dp/creational/AbstractFactory.cpp index e2f51f0..e9bb9f4 100644 --- a/src/dp/creational/AbstractFactory.cpp +++ b/src/dp/creational/AbstractFactory.cpp @@ -2,15 +2,7 @@ // Abstract Factory is a creational design pattern that lets you produce // families of related objects without specifying their concrete classes. -// Appicability: -// (*) when your code needs to work with various families of related products, -// but you don’t want it to depend on the concrete classes -// of those products—they might be unknown beforehand or you simply want to -// allow for future extensibility. -// (**) when you have a class with a set of Factory Methods that blur its -// primary responsibility. - -// UML: docs/uml/patterns_creational_abstractfactory.drawio.svg + #include #include #include "ExampleRegistry.h" @@ -18,19 +10,16 @@ namespace { namespace abstract_factory { -/** - * The Product interface declares the operations that all concrete products must - * implement. - */ + +/// @class Product Interface +/// @brief Declares the operations that all concrete products must implement class IGdbProduct { public: virtual ~IGdbProduct() = default; virtual void launch() const = 0; }; -/** - * Concrete Products provide various implementations of the Product interface. - */ +/// @brief The concrete product class LinuxGdbProduct : public IGdbProduct { public: void launch() const override { @@ -75,60 +64,62 @@ class MacOsCMakeProduct : public ICMakeProduct { } }; -// =================================================================================== - -/* - * Abstract Factory - * provides an abstract interface for creating a family of products - */ +/// @class Abstract Factory +/// @brief Provide abstract interface for creating a family of products class IProductAbstractFactory { public: virtual ~IProductAbstractFactory() = default; - virtual IGdbProduct* create_gdb_product() = 0; - virtual ICMakeProduct* create_cmake_product() = 0; + virtual std::unique_ptr create_gdb_product() = 0; + virtual std::unique_ptr create_cmake_product() = 0; }; -/* - * Concrete Factory - * each concrete factory create a family of products and client uses - * one of these factories so it never has to instantiate a product object - */ +/// @class Concrete Factory +/// @brief concrete factory create a family of products and client uses +/// one of these factories so it never has to instantiate a product object class WindowsProductFactory : public IProductAbstractFactory { public: - IGdbProduct* create_gdb_product() override { return new WindowsGdbProduct(); } - ICMakeProduct* create_cmake_product() override { - return new WindowsCMakeProduct(); + std::unique_ptr create_gdb_product() override { + return std::make_unique(); + } + std::unique_ptr create_cmake_product() override { + return std::make_unique(); } }; class LinuxProductFactory : public IProductAbstractFactory { public: - IGdbProduct* create_gdb_product() override { return new LinuxGdbProduct(); } - ICMakeProduct* create_cmake_product() override { - return new LinuxCMakeProduct(); + std::unique_ptr create_gdb_product() override { + return std::make_unique(); + } + + std::unique_ptr create_cmake_product() override { + return std::make_unique(); } }; class MacOsProductFactory : public IProductAbstractFactory { public: - IGdbProduct* create_gdb_product() override { return new MacOsGdbProduct(); } - ICMakeProduct* create_cmake_product() override { - return new MacOsCMakeProduct(); + std::unique_ptr create_gdb_product() override { + return std::make_unique(); } -}; -// =================================================================================== + std::unique_ptr create_cmake_product() override { + return std::make_unique(); + } +}; -// static redudant inside anonymous namespace -IProductAbstractFactory* create_product_factory(const std::string& os) { +/// @brief Factory selector +/// static redudant inside anonymous namespace +std::unique_ptr create_product_factory( + const std::string& os) { if (os == "linux") { - return new LinuxProductFactory(); + return std::make_unique(); } if (os == "windows") { - return new WindowsProductFactory(); + return std::make_unique(); } if (os == "macos") { - return new MacOsProductFactory(); + return std::make_unique(); } LOG("OS not support yet - " + os); @@ -138,25 +129,16 @@ IProductAbstractFactory* create_product_factory(const std::string& os) { void run() { LOG("Abstract Factory Pattern Example"); - /** - * The client code works with factories and products only through abstract - * types: AbstractFactory and AbstractProduct. This lets you pass any factory or - * product subclass to the client code without breaking it. - */ auto client_code = [](IProductAbstractFactory* f) { - ICMakeProduct* cmake = f->create_cmake_product(); - IGdbProduct* gdb = f->create_gdb_product(); + auto cmake = f->create_cmake_product(); + auto gdb = f->create_gdb_product(); cmake->launch(); gdb->launch(); - - delete cmake; - delete gdb; }; - std::string os = "linux"; - IProductAbstractFactory* factory = create_product_factory(os); - client_code(factory); - delete factory; + const std::string os = "linux"; + auto factory = create_product_factory(os); + client_code(factory.get()); } } // namespace abstract_factory } // namespace diff --git a/src/dp/creational/FactoryMethod.cpp b/src/dp/creational/FactoryMethod.cpp index f099ff1..16e897a 100644 --- a/src/dp/creational/FactoryMethod.cpp +++ b/src/dp/creational/FactoryMethod.cpp @@ -1,35 +1,20 @@ // cppcheck-suppress-file [functionStatic] -// Factory Method is a creational design pattern that provides an interface for -// creating objects in a superclass, but allows subclasses to alter the type of -// objects that will be created. Appicability: -// (*) when you don’t know beforehand the exact types and dependencies of the -// objects your code should work with. -// (**) when you want to provide users of your library or framework with a way -// to extend its internal components. -// (***)when you want to save system resources by reusing existing objects -// instead of rebuilding them each time. - -// UML: docs/uml/patterns_creational_factorymethod.drawio.svg - +#include #include +#include "ExampleRegistry.h" #include "Logger.h" namespace { namespace factory_method { -/** - * The Product interface declares the operations that all concrete products must - * implement. - */ + +/// @class Product Interface class IGdbProduct { public: virtual ~IGdbProduct() = default; virtual void launch() const = 0; }; -/** - * Concrete Products provide various implementations of the Product interface. - */ class LinuxGdbProduct : public IGdbProduct { public: void launch() const override { @@ -49,115 +34,95 @@ class MacOsGdbProduct : public IGdbProduct { void launch() const override { LOG("brew install gdb && gdb --version"); } }; -// =================================================================================== - -/** - * The Creator class declares the factory method that is supposed to return an - * object of a Product class. The Creator's subclasses usually provide the - * implementation of this method. (a.k.a IGdbFactory) - */ +/// @class Creator Interface class IGdbFactory { public: virtual ~IGdbFactory() = default; - virtual IGdbProduct* factory_method() = 0; + virtual std::unique_ptr factory_method() = 0; virtual void launch_gdb() = 0; }; class AbstractGdbFactory : public IGdbFactory { public: - // Call the factory method to create a Product object. + /// @brief call the factory method to create a Product object + /// execute operation void launch_gdb() final { - IGdbProduct* gdb = this->factory_method(); + auto gdb = this->factory_method(); gdb->launch(); - delete gdb; } }; -/** - * Concrete Creators override the factory method in order to change the - * resulting product's type. - */ class WindowsGdbFactory : public AbstractGdbFactory { public: - IGdbProduct* factory_method() override { return new WindowsGdbProduct(); } + std::unique_ptr factory_method() override { + return std::make_unique(); + } }; class LinuxGdbFactory : public AbstractGdbFactory { public: - IGdbProduct* factory_method() override { return new LinuxGdbProduct(); } + std::unique_ptr factory_method() override { + return std::make_unique(); + } }; class MacOsGdbFactory : public AbstractGdbFactory { public: - IGdbProduct* factory_method() override { return new MacOsGdbProduct(); } + std::unique_ptr factory_method() override { + return std::make_unique(); + } }; -// =================================================================================== - -IGdbFactory* create_gdb_factory(const std::string& os) { +/// @brief selector +std::unique_ptr create_gdb_factory(const std::string& os) { if (os == "linux") { - return new LinuxGdbFactory(); + return std::make_unique(); } if (os == "windows") { - return new WindowsGdbFactory(); + return std::make_unique(); } if (os == "macos") { - return new MacOsGdbFactory(); + return std::make_unique(); } LOG("OS not support yet - " + os); return nullptr; } void run() { - /** - * The client code works with an instance of a concrete creator, albeit through - * 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. - */ auto client_code = [](IGdbFactory* gdb) { - if (gdb != nullptr) + if (gdb != nullptr) { gdb->launch_gdb(); + } }; // Create factory base on the os { const std::string os = "linux"; - IGdbFactory* gdb = create_gdb_factory(os); + auto gdb = create_gdb_factory(os); - client_code(gdb); - - delete gdb; + client_code(gdb.get()); } { const std::string os = "windows"; - IGdbFactory* gdb = create_gdb_factory(os); - - client_code(gdb); + auto gdb = create_gdb_factory(os); - delete gdb; + client_code(gdb.get()); } { const std::string os = "macos"; - IGdbFactory* gdb = create_gdb_factory(os); + auto gdb = create_gdb_factory(os); - client_code(gdb); - - delete gdb; + client_code(gdb.get()); } { const std::string os = "unknown"; - IGdbFactory* gdb = create_gdb_factory(os); - - client_code(gdb); - - delete gdb; + auto gdb = create_gdb_factory(os); + client_code(gdb.get()); } } } // namespace factory_method } // namespace -#include "ExampleRegistry.h" - class FactoryMethodExample : public IExample { public: std::string group() const override { return "dp/creational"; } From fb694bb82ae201477680b9eca4c5b1946f477c56 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Jul 2026 20:54:35 +0700 Subject: [PATCH 16/18] Update for builder --- src/dp/creational/Builder.cpp | 79 +++++++++++------------------------ 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/src/dp/creational/Builder.cpp b/src/dp/creational/Builder.cpp index c9ee38e..cee7339 100644 --- a/src/dp/creational/Builder.cpp +++ b/src/dp/creational/Builder.cpp @@ -1,20 +1,14 @@ // cppcheck-suppress-file [functionStatic] -// Builder is a creational design pattern that lets you construct complex -// objects step by step. The pattern allows you to produce different types and -// representations of an object using the same construction code. Appicability: -// (*) Use the Builder pattern to get rid of a “telescoping constructor”. -// (**) when you want your code to be able to create different representations -// of some product (for example, stone and wooden houses). - -// UML: docs/uml/patterns_behavioral_iterator.drawio.svg - +#include #include #include #include #include #include "Logger.h" +#include "ExampleRegistry.h" + namespace { namespace builder_pattern { class Product { @@ -37,10 +31,8 @@ class Product { } }; -/** - * The Builder interface specifies methods for creating the different parts of - * the Product objects. - */ +/// @class Builder Interface +/// @brief specifics methods for creating the different parts class IBuilder { public: virtual ~IBuilder() = default; @@ -49,53 +41,30 @@ class IBuilder { virtual IBuilder& produce_part_2() = 0; virtual IBuilder& produce_part_3() = 0; - virtual Product* build() = 0; + virtual std::unique_ptr build() = 0; }; class AbstractBuilder : public IBuilder { protected: - Product* product_; + std::unique_ptr product_; public: - explicit AbstractBuilder() { product_ = new Product(); } - - ~AbstractBuilder() override { delete product_; } - - AbstractBuilder(const AbstractBuilder& other) { - - delete product_; - - product_ = new Product(); - *product_ = *other.product_; - } - - AbstractBuilder& operator=(const AbstractBuilder& other) { - if (this == &other) { - return *this; - } + explicit AbstractBuilder() : product_{std::make_unique()} {} - delete product_; - product_ = new Product(); - *product_ = *other.product_; + AbstractBuilder(const AbstractBuilder&) = delete; + AbstractBuilder& operator=(const AbstractBuilder&) = delete; - return *this; - } + AbstractBuilder(AbstractBuilder&&) = default; + AbstractBuilder& operator=(AbstractBuilder&&) = default; - // the child classes are no longer override this function + /// @brief the child classes are no longer override this function IBuilder& reset() final { - - delete product_; - product_ = new Product(); - + product_ = std::make_unique(); return *this; } }; -/** - * The Concrete Builder classes follow the Builder interface and provide - * specific implementations of the building steps. Your program may have several - * variations of Builders, implemented differently. - */ +/// @class Concrete Builder class SimpleBuilder : public AbstractBuilder { public: IBuilder& produce_part_1() override { @@ -113,7 +82,7 @@ class SimpleBuilder : public AbstractBuilder { return *this; } - Product* build() override { return product_; } + std::unique_ptr build() override { return std::move(product_); } }; class ComplexBuilder : public AbstractBuilder { @@ -133,23 +102,25 @@ class ComplexBuilder : public AbstractBuilder { return *this; } - Product* build() override { return product_; } + std::unique_ptr build() override { return std::move(product_); } }; void run() { auto client_code = [](IBuilder* const builder) { - const Product* p1 = + // product 1 + auto p1 = (*builder).produce_part_1().produce_part_2().produce_part_3().build(); p1->print(); - const Product* p2 = (*builder).reset().produce_part_1().build(); + + // product 2 + auto p2 = (*builder).reset().produce_part_1().build(); p2->print(); }; { LOG("ConcreteBuilder: Simple"); - IBuilder* builder = new SimpleBuilder(); - client_code(builder); - delete builder; + auto builder = std::make_unique(); + client_code(builder.get()); } { LOG("ConcreteBuilder: Complex"); @@ -161,8 +132,6 @@ void run() { } // namespace builder_pattern } // namespace -#include "ExampleRegistry.h" - class BuilderExample : public IExample { public: std::string group() const override { return "dp/creational"; } From 1beb831490dcc409848ca8f928bdddfbe4e5fad8 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Jul 2026 21:09:38 +0700 Subject: [PATCH 17/18] Update for singleton --- src/dp/creational/Singleton.cpp | 73 ++++++++++++--------------------- 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/src/dp/creational/Singleton.cpp b/src/dp/creational/Singleton.cpp index 1165215..d9a695d 100644 --- a/src/dp/creational/Singleton.cpp +++ b/src/dp/creational/Singleton.cpp @@ -1,69 +1,52 @@ // cppcheck-suppress-file [functionStatic] -// Singleton is a creational design pattern that lets you ensure that a class -// has only one instance, while providing a global access point to this -// instance. Appicability: -// (*) when a class in your program should have just a single instance -// available to all clients; for example, a single database object shared by -// different parts of the program. -// (**) when you need stricter control over global variables. - -// UML: docs/uml/patterns_creational_singleton.drawio.svg - #include +#include "ExampleRegistry.h" #include "Logger.h" namespace { namespace singleton_pattern { -/** - * The Singleton class defines the `GetInstance` method that serves as an - * alternative to constructor and lets clients access the same instance of this - * class over and over. - */ -class Singleton { - private: - static inline Singleton* instance_ = nullptr; - static inline int id_ = 0; - int dummy_{}; - /** - * The Singleton's constructor should always be private to prevent direct - * construction calls with the `new` operator. - */ - Singleton() = default; +/// @class Singleton class +/// @brief defines the `GetInstance` method that serves as an alternative to constructor +class SingletonConfig { public: // 1. Should not be cloneable. - Singleton(const Singleton& other) = delete; + SingletonConfig(const SingletonConfig& other) = delete; // 2. Should not be assignable - Singleton& operator=(const Singleton& other) = delete; + SingletonConfig& operator=(const SingletonConfig& other) = delete; - static Singleton* get_instance() { - if (instance_ == nullptr) { - instance_ = new Singleton(); - id_++; - } - LOG("id: " + std::to_string(id_)); - return instance_; + static SingletonConfig& get_instance() { + static SingletonConfig instance; + return instance; } - void operation() { - LOG("id: " + std::to_string(id_)); - dummy_++; + void init(const std::string& input) { + LOG(input); + value_ = input; } + + const std::string& get_value() const { + LOG(""); + return value_; + }; + + private: + /// @brief Default constructor should always be private + SingletonConfig() = default; + std::string value_; }; void run() { - auto client_code = [](Singleton* s) { - s->operation(); + auto client_code = []() { + LOG(SingletonConfig::get_instance().get_value()); }; - Singleton* s1 = Singleton::get_instance(); - client_code(s1); - - Singleton* s2 = Singleton::get_instance(); - client_code(s2); + SingletonConfig& s1 = SingletonConfig::get_instance(); + s1.init("0x001"); + client_code(); // Singleton* s3 = new Singleton(); // ERROR } @@ -71,8 +54,6 @@ void run() { } // namespace singleton_pattern } // namespace -#include "ExampleRegistry.h" - class SingletonExample : public IExample { public: std::string group() const override { return "dp/creational"; } From c524c818f4c57742fac00752f6a586bb332da06f Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sun, 26 Jul 2026 21:22:42 +0700 Subject: [PATCH 18/18] Update descriptions --- src/dp/creational/AbstractFactory.cpp | 10 +- src/dp/creational/Builder.cpp | 7 ++ src/dp/creational/FactoryMethod.cpp | 7 ++ src/dp/creational/Prototype.cpp | 148 +++++++++++++------------- src/dp/creational/Singleton.cpp | 8 ++ 5 files changed, 102 insertions(+), 78 deletions(-) diff --git a/src/dp/creational/AbstractFactory.cpp b/src/dp/creational/AbstractFactory.cpp index e9bb9f4..ffb5626 100644 --- a/src/dp/creational/AbstractFactory.cpp +++ b/src/dp/creational/AbstractFactory.cpp @@ -1,7 +1,13 @@ // cppcheck-suppress-file [functionStatic] -// Abstract Factory is a creational design pattern that lets you produce -// families of related objects without specifying their concrete classes. +// Abstract Factory — create families of related products without concrete types. +// +// Flow in this file: +// 1. Define product interfaces -> IGdbProduct, ICMakeProduct +// 2. Implement concrete products per OS -> Linux / Windows / MacOs variants +// 3. Define an abstract factory -> IProductAbstractFactory +// 4. Implement concrete factories -> one factory = one matching family +// 5. Client uses one factory for all products -> products stay consistent (same OS) #include #include diff --git a/src/dp/creational/Builder.cpp b/src/dp/creational/Builder.cpp index cee7339..ae861a2 100644 --- a/src/dp/creational/Builder.cpp +++ b/src/dp/creational/Builder.cpp @@ -1,5 +1,12 @@ // cppcheck-suppress-file [functionStatic] +// Flow in this file: +// 1. Define the product being built -> Product (parts list) +// 2. Define a builder interface -> IBuilder (produce_part_N / build) +// 3. Share common builder state -> AbstractBuilder (reset / product_) +// 4. Implement concrete builders -> SimpleBuilder / ComplexBuilder +// 5. Client chains steps, then build() -> same steps, different representations + #include #include #include diff --git a/src/dp/creational/FactoryMethod.cpp b/src/dp/creational/FactoryMethod.cpp index 16e897a..5c13432 100644 --- a/src/dp/creational/FactoryMethod.cpp +++ b/src/dp/creational/FactoryMethod.cpp @@ -1,5 +1,12 @@ // cppcheck-suppress-file [functionStatic] +// Flow in this file: +// 1. Define a product interface -> IGdbProduct +// 2. Implement concrete products -> Linux / Windows / MacOs Gdb +// 3. Define a creator interface -> IGdbFactory (+ AbstractGdbFactory) +// 4. Implement concrete creators -> Linux / Windows / MacOs factories +// 5. Client picks a factory, then uses it -> never constructs products directly + #include #include #include "ExampleRegistry.h" diff --git a/src/dp/creational/Prototype.cpp b/src/dp/creational/Prototype.cpp index 5cb57bd..3816684 100644 --- a/src/dp/creational/Prototype.cpp +++ b/src/dp/creational/Prototype.cpp @@ -1,135 +1,131 @@ // cppcheck-suppress-file [functionStatic] -// Prototype is a creational design pattern that lets you "copy existing objects" without making your code "dependent on their classes". -// Appicability: -// (*) when your code shouldn’t depend on the concrete classes of objects that you need to copy. -// (**) when you want to reduce the number of subclasses that only differ in the way they initialize their respective objects. - -// UML: docs/uml/patterns_behavioral_prototype.drawio.svg - +// Prototype = create new objects by cloning existing ones. +// +// Flow in this file: +// 1. Define a cloneable interface -> IExtensionPrototype +// 2. Implement concrete prototypes -> Logger / Analytics +// 3. (Optional) Store named presets -> ExtensionPrototypeRegistry +// 4. Client asks registry to clone by id -> never mentions concrete types + +#include +#include +#include #include #include + +#include "ExampleRegistry.h" #include "Logger.h" + namespace { namespace prototy { -constexpr std::string_view kLoggerEtxId = "logger"; +constexpr std::string_view kLoggerExtId = "logger"; constexpr std::string_view kAnalyzeId = "analyze"; -/* - * Prototype interface declares the cloning methods. - * In most cases, it’s a single `clone` method. - */ +/// @class Prototype interface: "I know how to copy myself." +/// @brief client code only depends on this class class IExtensionPrototype { public: virtual ~IExtensionPrototype() = default; - virtual IExtensionPrototype* clone() = 0; + + /// return a new object + virtual std::unique_ptr clone() const = 0; + virtual void execute() const = 0; }; -/* - * Concrete Prototype implement an operation for cloning itself - * In addition to copying the original object’s data to the clone, - * this method may also handle some edge cases of the cloning process related to cloning linked objects, - * untangling recursive dependencies, etc. - */ +/// @class Concrete Prototype +/// @brief each class copies itself class LoggerExtension : public IExtensionPrototype { - private: - std::string log_level_; - public: explicit LoggerExtension(std::string level = "DEBUG") : log_level_{std::move(level)} {} - IExtensionPrototype* clone() override { return new LoggerExtension(*this); } + std::unique_ptr clone() const override { + return std::make_unique(*this); + } void execute() const override { LOG("log level: " + log_level_); } -}; -class AnalyticsExtension : public IExtensionPrototype { private: - int sRate_; + std::string log_level_; +}; +class AnalyticsExtension : public IExtensionPrototype { public: - explicit AnalyticsExtension(int level = 1) : sRate_{level} {} + explicit AnalyticsExtension(int sampling_rate = 1) + : sampling_rate_{sampling_rate} {} - IExtensionPrototype* clone() override { - return new AnalyticsExtension(*this); + std::unique_ptr clone() const override { + return std::make_unique(*this); } - void execute() const override { LOG_S("sampling rate: " << sRate_); } -}; + void execute() const override { LOG_S("sampling rate: " << sampling_rate_); } -/** - * Prototype Registry provides an easy way to access frequently-used prototypes. - * It stores a set of pre-built objects that are ready to be copied. - * The simplest prototype registry is a name ^ prototype hash map. - * However, if you need better search criteria than a simple name, you can build a much more robust version of the registry. - */ -class ExtensionPrototypeRegistry { private: - std::unordered_map prototypes_; + int sampling_rate_; +}; +/// @class Prototype Registry +/// @brief a map of named presets ready to be cloned. +class ExtensionPrototypeRegistry { 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 - } - } - void register_extension(const std::string_view& id, - IExtensionPrototype* proto) { + void register_extension(std::string_view id, + std::unique_ptr proto) { LOG(id); - prototypes_[std::string(id)] = proto; + prototypes_[std::string(id)] = std::move(proto); } - IExtensionPrototype* create(const std::string_view& id) const { + /// clone the preset for `id`. Returns nullptr if the id is unknown. + std::unique_ptr create(std::string_view id) const { auto it = prototypes_.find(std::string(id)); - if (it != prototypes_.end()) { - return it->second->clone(); + if (it == prototypes_.end()) { + return nullptr; } - return nullptr; + return it->second->clone(); // copy the template, leave the original intact } + + private: + std::unordered_map> + prototypes_; }; void run() { - // Client creates a new object by asking a prototype to clone itself - auto client_code = [](const ExtensionPrototypeRegistry* const registry) { - IExtensionPrototype* logger_etx = registry->create(prototy::kLoggerEtxId); - logger_etx->execute(); - IExtensionPrototype* analyx_etx = registry->create(prototy::kAnalyzeId); - analyx_etx->execute(); - - delete logger_etx; - delete analyx_etx; + // build presets once, register by name + ExtensionPrototypeRegistry registry; + registry.register_extension(kLoggerExtId, + std::make_unique("DEBUG")); + registry.register_extension(kAnalyzeId, + std::make_unique(1200)); + + // create-by-clone + auto client_code = [](const ExtensionPrototypeRegistry& reg) { + auto logger_ext = reg.create(kLoggerExtId); + auto analytics_ext = reg.create(kAnalyzeId); + + if (logger_ext) { + logger_ext->execute(); + } + if (analytics_ext) { + analytics_ext->execute(); + } }; - // Create a registry - auto* registry = new ExtensionPrototypeRegistry(); - - // Register extensions - registry->register_extension(prototy::kLoggerEtxId, - new LoggerExtension("DEBUG")); - registry->register_extension(prototy::kAnalyzeId, - new AnalyticsExtension(1200)); - client_code(registry); - - delete registry; } + } // namespace prototy } // namespace -#include "ExampleRegistry.h" - class PrototypeExample : public IExample { public: std::string group() const override { return "dp/creational"; } std::string name() const override { return "Prototype"; } std::string description() const override { - return "Prototype Pattern Example"; + return "Clone configured objects via a prototype interface + registry"; } void execute() override { prototy::run(); } }; -REGISTER_EXAMPLE(PrototypeExample); \ No newline at end of file +REGISTER_EXAMPLE(PrototypeExample); diff --git a/src/dp/creational/Singleton.cpp b/src/dp/creational/Singleton.cpp index d9a695d..b3bc6ac 100644 --- a/src/dp/creational/Singleton.cpp +++ b/src/dp/creational/Singleton.cpp @@ -1,5 +1,13 @@ // cppcheck-suppress-file [functionStatic] +// Singleton — ensure a class has only one instance, accessed globally. +// +// Flow in this file: +// 1. Hide the constructor -> private SingletonConfig() +// 2. Ban copy / assign -> deleted special members +// 3. Expose a single access point -> get_instance() (Meyers' singleton) +// 4. Client always uses get_instance() -> same object everywhere + #include #include "ExampleRegistry.h" #include "Logger.h"