From 62ab80b1d68a9d1a85b78e0ddac8d326abbf4773 Mon Sep 17 00:00:00 2001 From: dl92 Date: Tue, 6 Jan 2026 15:05:27 +0000 Subject: [PATCH] initial commit --- cplusplus/geminitutorial/README.md | 2 + cplusplus/geminitutorial/gemini.md | 89 ++++++++ cplusplus/geminitutorial/plan.md | 69 ++++++ .../tutorial1/.vscode/settings.json | 6 + .../geminitutorial/tutorial1/CMakeLists.txt | 33 +++ .../tutorial1/src/calculator.cpp | 5 + .../geminitutorial/tutorial1/src/calculator.h | 9 + .../geminitutorial/tutorial1/src/main.cpp | 16 ++ .../tutorial1/test/test_calculator.cpp | 22 ++ .../tutorial1/tutorial-part1-1.md | 173 +++++++++++++++ .../tutorial1/tutorial-part1-2.md | 201 +++++++++++++++++ .../tutorial2/.vscode/settings.json | 6 + .../geminitutorial/tutorial2/CMakeLists.txt | 31 +++ .../tutorial2/src/CsvParser.cpp | 73 +++++++ .../geminitutorial/tutorial2/src/CsvParser.h | 11 + .../tutorial2/src/StockData_Modern.cpp | 9 + .../tutorial2/src/StockData_Modern.h | 19 ++ .../tutorial2/src/StockData_Old.cpp | 37 ++++ .../tutorial2/src/StockData_Old.h | 25 +++ .../geminitutorial/tutorial2/src/TickData.h | 25 +++ .../geminitutorial/tutorial2/src/Trade.h | 26 +++ .../geminitutorial/tutorial2/src/main.cpp | 202 ++++++++++++++++++ .../tutorial2/tutorial-2.1-plan.md | 109 ++++++++++ .../tutorial2/tutorial-2.2-followup.md | 10 + .../tutorial2/tutorial-2.2-plan.md | 83 +++++++ 25 files changed, 1291 insertions(+) create mode 100644 cplusplus/geminitutorial/README.md create mode 100644 cplusplus/geminitutorial/gemini.md create mode 100644 cplusplus/geminitutorial/plan.md create mode 100644 cplusplus/geminitutorial/tutorial1/.vscode/settings.json create mode 100644 cplusplus/geminitutorial/tutorial1/CMakeLists.txt create mode 100644 cplusplus/geminitutorial/tutorial1/src/calculator.cpp create mode 100644 cplusplus/geminitutorial/tutorial1/src/calculator.h create mode 100644 cplusplus/geminitutorial/tutorial1/src/main.cpp create mode 100644 cplusplus/geminitutorial/tutorial1/test/test_calculator.cpp create mode 100644 cplusplus/geminitutorial/tutorial1/tutorial-part1-1.md create mode 100644 cplusplus/geminitutorial/tutorial1/tutorial-part1-2.md create mode 100644 cplusplus/geminitutorial/tutorial2/.vscode/settings.json create mode 100644 cplusplus/geminitutorial/tutorial2/CMakeLists.txt create mode 100644 cplusplus/geminitutorial/tutorial2/src/CsvParser.cpp create mode 100644 cplusplus/geminitutorial/tutorial2/src/CsvParser.h create mode 100644 cplusplus/geminitutorial/tutorial2/src/StockData_Modern.cpp create mode 100644 cplusplus/geminitutorial/tutorial2/src/StockData_Modern.h create mode 100644 cplusplus/geminitutorial/tutorial2/src/StockData_Old.cpp create mode 100644 cplusplus/geminitutorial/tutorial2/src/StockData_Old.h create mode 100644 cplusplus/geminitutorial/tutorial2/src/TickData.h create mode 100644 cplusplus/geminitutorial/tutorial2/src/Trade.h create mode 100644 cplusplus/geminitutorial/tutorial2/src/main.cpp create mode 100644 cplusplus/geminitutorial/tutorial2/tutorial-2.1-plan.md create mode 100644 cplusplus/geminitutorial/tutorial2/tutorial-2.2-followup.md create mode 100644 cplusplus/geminitutorial/tutorial2/tutorial-2.2-plan.md diff --git a/cplusplus/geminitutorial/README.md b/cplusplus/geminitutorial/README.md new file mode 100644 index 0000000..15b9de7 --- /dev/null +++ b/cplusplus/geminitutorial/README.md @@ -0,0 +1,2 @@ +# GeminiTutorial + diff --git a/cplusplus/geminitutorial/gemini.md b/cplusplus/geminitutorial/gemini.md new file mode 100644 index 0000000..0404474 --- /dev/null +++ b/cplusplus/geminitutorial/gemini.md @@ -0,0 +1,89 @@ +# Gemini C++ Refresher Plan + +This document summarizes the C++ refresher plan designed for an experienced programmer returning to C++ with a focus on quantitative finance (Quant) and High-Frequency Trading (HFT). + +## Initial Request + +The user, an experienced programmer last active with C++ around the year 2000, requested a detailed plan to get up to speed with modern C++. The plan needed to cover: + +1. Build tools and development setup on Linux (VSCode/terminal). +2. Modern programming constructs and concepts. +3. Usage of modern standard libraries. +4. A strong emphasis on design patterns and idioms for efficient, low-latency code. + +The context is for application in quantitative modeling and HFT. + +## Review of Expert Material + +The initial plan was subsequently refined by reviewing two expert documents provided by the user: + +1. **"Optimizing C++" by Agner Fog:** A guide to low-level, hardware-aware C++ optimization. +2. **"Modern C++ for Financial Engineering" (arXiv:2309.04259):** A domain-specific paper on modern C++ patterns in finance. + +## Final Refresher Plan + +The final plan incorporates insights from these documents, focusing on practical, hands-on tutorials that build upon each other. + +--- + +### **Part 1: The Modern Development Environment on Linux** + +This part establishes a professional, reproducible development workflow. + +* **Tutorial 1.1: Your First Modern C++ Project** + * **Objective:** Build a simple program using the modern toolchain (CMake, vcpkg) and link an external library (`spdlog`). + * **Tools:** `g++`/`clang++`, `CMake`, `vcpkg`, VSCode with C++ & CMake extensions. + * **Key Takeaway:** Automate building and dependency management, leaving manual Makefiles in the past. + +--- + +### **Part 2: Core Language, Libraries, and Concepts** + +This section bridges the 20-year gap from C++98 to C++20+. + +* **Tutorial 2.1: Resource Management & The Rule of Zero (Completed)**** + * **Objective:** Master RAII and move semantics to eliminate manual memory management. + * **Concepts:** Smart Pointers (`std::unique_ptr`, `std::shared_ptr`), Move Semantics (`&&`, `std::move`), and The Rule of Zero. + * **Project:** Refactor a C++98-style class using raw pointers to a modern class using `std::vector` and smart pointers, demonstrating the elimination of manual destructors/constructors. + +* **Tutorial 2.2: Modern STL Containers & Algorithms** + * **Objective:** Use the workhorse containers and algorithms with a focus on performance. + * **Concepts:** `std::vector`, `std::array` (for stack allocation), `std::string_view` (for zero-copy parsing), `std::unordered_map`, Lambdas, and range-based `for` loops. + * **Project:** Parse mock CSV tick data, using algorithms and lambdas to perform queries. + +* **Tutorial 2.3: Compile-Time Programming & Type Safety** + * **Objective:** Use the compiler to improve performance and safety. + * **Concepts:** `constexpr` for compile-time calculations, `enum class` for type-safe enums, `auto` for type deduction. + * **Project:** A simple program using these features to enforce type safety and move runtime calculations to compile-time. + +--- + +### **Part 3: Design Patterns & Idioms for Low-Latency C++ (Revised)** + +This section focuses on HFT/Quant performance, emphasizing hardware-aware programming. + +* **Tutorial 3.1: Static vs. Dynamic Polymorphism (CRTP vs. Virtual Functions)** + * **Objective:** Understand the performance cost of `virtual` functions and learn the **Curiously Recurring Template Pattern (CRTP)** as a zero-cost, compile-time alternative. + * **Hardware Insight:** `virtual` calls can cause branch mispredictions; CRTP enables inlining. + +* **Tutorial 3.2: Custom Memory Management & Cache Locality** + * **Objective:** Understand that heap allocation (`new`) is slow primarily because it destroys **cache locality**. + * **Concepts:** Memory Pools / Arena Allocators. The key benefit is placing related data contiguously in memory to maximize CPU cache efficiency. + +* **Tutorial 3.3: Data-Oriented Design (Struct of Arrays)** + * **Objective:** Implement a powerful, cache-friendly optimization by changing data layout. + * **Concepts:** Switch from Array of Structs (AoS), e.g., `vector`, to Struct of Arrays (SoA), e.g., `struct { vector prices; vector volumes; }`. + * **Project:** Benchmark a calculation on a large dataset using both AoS and SoA layouts to demonstrate the significant performance gain of SoA, which is ideal for cache utilization and SIMD vectorization. + +* **Tutorial 3.4: Type-Safe Polymorphism with `std::variant`** + * **Objective:** Learn the modern, safe, and performant way to handle objects of different types (e.g., financial events). + * **Concepts:** `std::variant` as a type-safe union and `std::visit` to operate on the contained types without `virtual` functions or unsafe casts. + +--- + +### **Part 4: Additional Essential Material (Revised)** + +* **Concurrency:** `std::thread`, `std::mutex`, `std::atomic` (critical for lock-free code), `std::condition_variable`. +* **Essential Quant Libraries:** **Eigen** for linear algebra, **Boost** for various utilities. +* **Advanced Topic - Adjoint Algorithmic Differentiation (AAD):** An introduction to the key technique used in modern derivatives pricing for calculating risk sensitivities ("Greeks") efficiently. +* **Further Reading:** `cppreference.com`, "Effective Modern C++" (Scott Meyers), CppCon talks. diff --git a/cplusplus/geminitutorial/plan.md b/cplusplus/geminitutorial/plan.md new file mode 100644 index 0000000..1882c53 --- /dev/null +++ b/cplusplus/geminitutorial/plan.md @@ -0,0 +1,69 @@ +# C++ Refresher Plan for Quantitative/HFT Development + +This plan is designed for an experienced programmer returning to C++ with a focus on quantitative finance (Quant) and High-Frequency Trading (HFT). It incorporates expert feedback from "Optimizing C++" by Agner Fog and "Modern C++ for Financial Engineering" (arXiv:2309.04259). + +--- + +### **Part 1: The Modern Development Environment on Linux** + +This part establishes a professional, reproducible development workflow. + +* **Tutorial 1.1: Your First Modern C++ Project** + * **Objective:** Build a simple program using the modern toolchain (CMake, vcpkg) and link an external library (`spdlog`). + * **Tools:** `g++`/`clang++`, `CMake`, `vcpkg`, VSCode with C++ & CMake extensions. + * **Key Takeaway:** Automate building and dependency management, leaving manual Makefiles in the past. + +* **Tutorial 1.2: incorporate gtest unit testing framework** + +--- + +### **Part 2: Core Language, Libraries, and Concepts** + +This section bridges the 20-year gap from C++98 to C++20+. + +* **Tutorial 2.1: Resource Management & The Rule of Zero** + * **Objective:** Master RAII and move semantics to eliminate manual memory management. + * **Concepts:** Smart Pointers (`std::unique_ptr`, `std::shared_ptr`), Move Semantics (`&&`, `std::move`), and The Rule of Zero. + * **Project:** Refactor a C++98-style class using raw pointers to a modern class using `std::vector` and smart pointers, demonstrating the elimination of manual destructors/constructors. + +* **Tutorial 2.2: Modern STL Containers & Algorithms** + * **Objective:** Use the workhorse containers and algorithms with a focus on performance. + * **Concepts:** `std::vector`, `std::array` (for stack allocation), `std::string_view` (for zero-copy parsing), `std::unordered_map`, Lambdas, and range-based `for` loops. + * **Project:** Parse mock CSV tick data, using algorithms and lambdas to perform queries. + +* **Tutorial 2.3: Compile-Time Programming & Type Safety** + * **Objective:** Use the compiler to improve performance and safety. + * **Concepts:** `constexpr` for compile-time calculations, `enum class` for type-safe enums, `auto` for type deduction. + * **Project:** A simple program using these features to enforce type safety and move runtime calculations to compile-time. + +--- + +### **Part 3: Design Patterns & Idioms for Low-Latency C++ (Revised)** + +This section focuses on HFT/Quant performance, emphasizing hardware-aware programming. + +* **Tutorial 3.1: Static vs. Dynamic Polymorphism (CRTP vs. Virtual Functions)** + * **Objective:** Understand the performance cost of `virtual` functions and learn the **Curiously Recurring Template Pattern (CRTP)** as a zero-cost, compile-time alternative. + * **Hardware Insight:** `virtual` calls can cause branch mispredictions; CRTP enables inlining. + +* **Tutorial 3.2: Custom Memory Management & Cache Locality** + * **Objective:** Understand that heap allocation (`new`) is slow primarily because it destroys **cache locality**. + * **Concepts:** Memory Pools / Arena Allocators. The key benefit is placing related data contiguously in memory to maximize CPU cache efficiency. + +* **Tutorial 3.3: Data-Oriented Design (Struct of Arrays)** + * **Objective:** Implement a powerful, cache-friendly optimization by changing data layout. + * **Concepts:** Switch from Array of Structs (AoS), e.g., `vector`, to Struct of Arrays (SoA), e.g., `struct { vector prices; vector volumes; }`. + * **Project:** Benchmark a calculation on a large dataset using both AoS and SoA layouts to demonstrate the significant performance gain of SoA, which is ideal for cache utilization and SIMD vectorization. + +* **Tutorial 3.4: Type-Safe Polymorphism with `std::variant`** + * **Objective:** Learn the modern, safe, and performant way to handle objects of different types (e.g., financial events). + * **Concepts:** `std::variant` as a type-safe union and `std::visit` to operate on the contained types without `virtual` functions or unsafe casts. + +--- + +### **Part 4: Additional Essential Material (Revised)** + +* **Concurrency:** `std::thread`, `std::mutex`, `std::atomic` (critical for lock-free code), `std::condition_variable`. +* **Essential Quant Libraries:** **Eigen** for linear algebra, **Boost** for various utilities. +* **Advanced Topic - Adjoint Algorithmic Differentiation (AAD):** An introduction to the key technique used in modern derivatives pricing for calculating risk sensitivities ("Greeks") efficiently. +* **Further Reading:** `cppreference.com`, "Effective Modern C++" (Scott Meyers), CppCon talks. diff --git a/cplusplus/geminitutorial/tutorial1/.vscode/settings.json b/cplusplus/geminitutorial/tutorial1/.vscode/settings.json new file mode 100644 index 0000000..5457383 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cmake.sourceDirectory": "/home/ys/code/cplusplus/GeminiTutorial/tutorial-1", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=/home/ys/code/cplusplus/vcpkg/scripts/buildsystems/vcpkg.cmake" + ] +} \ No newline at end of file diff --git a/cplusplus/geminitutorial/tutorial1/CMakeLists.txt b/cplusplus/geminitutorial/tutorial1/CMakeLists.txt new file mode 100644 index 0000000..61424d3 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.15) +project(Tutorial1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Find dependencies +find_package(spdlog CONFIG REQUIRED) +find_package(GTest CONFIG REQUIRED) + +# Create a library for our application code +# This allows us to share the code between the main app and the tests +add_library(MyLib src/calculator.cpp src/calculator.h) +target_include_directories(MyLib PUBLIC src) + +# Define our main executable +add_executable(App src/main.cpp) + +# Link our App against spdlog and our library +target_link_libraries(App PRIVATE spdlog::spdlog MyLib) + +# Enable testing with CTest (CMake's testing framework) +enable_testing() + +# Define the test executable +add_executable(RunTests test/test_calculator.cpp) + +# Link our test executable against GTest and our library +target_link_libraries(RunTests PRIVATE GTest::gtest_main MyLib) + +# Add the test to CTest +include(GoogleTest) +gtest_add_tests(TARGET RunTests) \ No newline at end of file diff --git a/cplusplus/geminitutorial/tutorial1/src/calculator.cpp b/cplusplus/geminitutorial/tutorial1/src/calculator.cpp new file mode 100644 index 0000000..9ae5c08 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/src/calculator.cpp @@ -0,0 +1,5 @@ +#include "calculator.h" + +int Calculator::add(int a, int b) { + return a + b; +} diff --git a/cplusplus/geminitutorial/tutorial1/src/calculator.h b/cplusplus/geminitutorial/tutorial1/src/calculator.h new file mode 100644 index 0000000..cb279dd --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/src/calculator.h @@ -0,0 +1,9 @@ +#ifndef CALCULATOR_H +#define CALCULATOR_H + +class Calculator { +public: + int add(int a, int b); +}; + +#endif // CALCULATOR_H diff --git a/cplusplus/geminitutorial/tutorial1/src/main.cpp b/cplusplus/geminitutorial/tutorial1/src/main.cpp new file mode 100644 index 0000000..9fb8c48 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/src/main.cpp @@ -0,0 +1,16 @@ +#include +#include "spdlog/spdlog.h" +#include "calculator.h" + +int main() { + spdlog::info("Hello, Modern C++! Initializing trading strategy..."); + + Calculator calc; + int result = calc.add(40, 2); + + spdlog::info("The result of 40 + 2 is: {}", result); + + std::cout << "Check your terminal for spdlog output!" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/cplusplus/geminitutorial/tutorial1/test/test_calculator.cpp b/cplusplus/geminitutorial/tutorial1/test/test_calculator.cpp new file mode 100644 index 0000000..abe8ba9 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/test/test_calculator.cpp @@ -0,0 +1,22 @@ +#include +#include "../src/calculator.h" // Include the header for the class we are testing + +// Test fixture for Calculator class +class CalculatorTest : public ::testing::Test { +protected: + Calculator calc; +}; + +// Test case for the add method +TEST_F(CalculatorTest, Add) { + EXPECT_EQ(calc.add(2, 2), 4); + EXPECT_EQ(calc.add(-1, 1), 0); + EXPECT_EQ(calc.add(-5, -5), -10); +} + +// Another test case for the add method for good measure +TEST_F(CalculatorTest, AddWithZero) { + EXPECT_EQ(calc.add(0, 5), 5); + EXPECT_EQ(calc.add(5, 0), 5); + EXPECT_EQ(calc.add(0, 0), 0); +} diff --git a/cplusplus/geminitutorial/tutorial1/tutorial-part1-1.md b/cplusplus/geminitutorial/tutorial1/tutorial-part1-1.md new file mode 100644 index 0000000..d57adc6 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/tutorial-part1-1.md @@ -0,0 +1,173 @@ +# Tutorial 1.1: Your First Modern C++ Project + +**Objective:** To compile, run, debug, and manage dependencies for a C++ application using the modern, industry-standard toolchain on Linux. This single tutorial covers the entire end-to-end workflow. + +--- + +## 1. Prerequisites: System Setup + +First, you need to ensure the necessary base tools are installed. Open your terminal and run the following commands. + +```bash +# Update package lists +sudo apt update + +# Install compiler (g++), make, git, and other essential build tools +sudo apt install build-essential g++ git cmake curl +``` + +You will also need **Visual Studio Code**, which you can download from the [official website](https://code.visualstudio.com/). + +After installing VSCode, launch it and install these two essential extensions from the Extensions view (Ctrl+Shift+X): +1. `C/C++` (Publisher: Microsoft) +2. `CMake Tools` (Publisher: Microsoft) + +## 2. The Game Changer: `vcpkg` Package Manager + +In C++ circa 2000, adding a library was a manual ordeal. `vcpkg` automates this. It downloads, builds, and prepares libraries for your project, acting like `pip` for Python. + +In your terminal, choose a location for your development tools (e.g., `~/dev/tools`) and clone `vcpkg`: + +```bash +# Create a directory for tools if you don't have one +mkdir -p ~/dev/tools +cd ~/dev/tools + +# Clone the vcpkg repository +git clone https://github.com/microsoft/vcpkg.git + +# Run the bootstrap script to build vcpkg itself +./vcpkg/bootstrap-vcpkg.sh +``` + +**IMPORTANT:** Note the absolute path to your vcpkg installation. You'll need it later. It will be something like `/home/YOUR_USERNAME/dev/tools/vcpkg`. + +## 3. Project Setup + +Now, let's create the project. + +```bash +# Go to where you keep your code projects +cd ~/code/cplusplus/GeminiTutorial + +# Create and enter the project directory +mkdir tutorial-1 +cd tutorial-1 +``` + +## 4. Installing a Library + +Let's install `spdlog`, a popular and high-performance logging library. + +```bash +# Use the vcpkg executable to install the library +# Replace /path/to/vcpkg with your actual vcpkg path +/home/YOUR_USERNAME/dev/tools/vcpkg/vcpkg install spdlog +``` + +This command will download, compile, and install `spdlog` into your `vcpkg` directory, making it available for any project. + +## 5. Writing the Build Script (`CMakeLists.txt`) + +This file tells `CMake` how to build your project. Create a file named `CMakeLists.txt` inside the `tutorial-1` directory with the following content. + +```cmake +# Specifies the minimum version of CMake required. +cmake_minimum_required(VERSION 3.15) + +# Defines the project name and sets C++ as the language. +project(Tutorial1 LANGUAGES CXX) + +# Set the C++ standard to C++17. Modern C++ starts with C++11. +# C++17 is a great, stable choice. +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Find the spdlog library. +# CMake needs to be told how to find packages installed by vcpkg. +# We will do this in the VSCode settings in the next step. +# 'CONFIG REQUIRED' means it's a fatal error if the package isn't found. +find_package(spdlog CONFIG REQUIRED) + +# Define our executable target, named 'App', from the source file 'main.cpp'. +add_executable(App main.cpp) + +# Link our App against the spdlog library. +# This tells the compiler to include the necessary spdlog files when building App. +target_link_libraries(App PRIVATE spdlog::spdlog) +``` + +## 6. Writing the C++ Code (`main.cpp`) + +Create a file named `main.cpp` in the `tutorial-1` directory. + +```cpp +#include + +// Include the main header from the spdlog library. +#include "spdlog/spdlog.h" + +int main() { + // Use the library to print an informational message. + // This is much more powerful than std::cout for real applications, + // as it can be configured to log to files, rotate logs, filter by level, etc. + spdlog::info("Hello, Modern C++! Initializing trading strategy..."); + + int x = 42; + double price = 102.5; + + // spdlog supports formatted output similar to Python's f-strings. + spdlog::warn("A variable 'x' has value: {}", x); + spdlog::critical("Critical event! Price is: {}", price); + + std::cout << "Check your terminal for spdlog output!" << std::endl; + + return 0; +} +``` + +## 7. Building and Debugging in VSCode + +This is where all the pieces come together. + +1. **Open the Project:** Launch VSCode and open the `tutorial-1` folder (`File > Open Folder...`). + +2. **Configure CMake:** + * The CMake Tools extension will activate. You may see a prompt asking to configure the project. + * **This will fail initially!** This is expected. An error will appear saying `Could not find a package configuration file for "spdlog"`. + * **Here is the fix:** We must tell CMake where to find `vcpkg`-installed libraries. + * Open the VSCode settings: `File > Preferences > Settings` (or `Ctrl+,`). + * Click the "Workspace" tab. Search for `cmake.configureArgs`. + * Click "Edit in settings.json". + * Add the following entry, **replacing the path with the actual absolute path to your vcpkg directory**: + ```json + { + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=/home/YOUR_USERNAME/dev/tools/vcpkg/scripts/buildsystems/vcpkg.cmake" + ] + } + ``` + * Save `settings.json`. A new `.vscode` directory will be created in your project folder to store this setting. + +3. **Build the Project:** + * Run the `CMake: Configure` command from the command palette (Ctrl+Shift+P). It should now succeed. + * The status bar at the bottom of VSCode now shows buttons for building. Click the **`Build`** button. + * You'll see output in the terminal as CMake and the compiler build your `App` executable. + +4. **Run and Debug:** + * **Run:** The "play" button in the status bar will run the executable. You'll see the `spdlog` output in the VSCode terminal. + * **Debug:** + 1. Open `main.cpp`. + 2. Click in the gutter to the left of the line number for `int x = 42;` to set a **breakpoint** (a red dot will appear). + 3. Press **F5** (or click the "bug" icon next to the play button). + 4. Execution will start and then **stop** at your breakpoint. + 5. You can now inspect variables in the "Run and Debug" side panel and use the controls to step through the code (F10, F11). + +--- + +**Congratulations!** You have successfully set up a modern C++ development environment, managed an external dependency, and used the integrated build/debug tools. This workflow is the foundation for all subsequent tutorials. + + +# 8 Feedback + +There is a dependency on gdb debugger that was not mentioned. after building and installing everything works as expected \ No newline at end of file diff --git a/cplusplus/geminitutorial/tutorial1/tutorial-part1-2.md b/cplusplus/geminitutorial/tutorial1/tutorial-part1-2.md new file mode 100644 index 0000000..3c44e9d --- /dev/null +++ b/cplusplus/geminitutorial/tutorial1/tutorial-part1-2.md @@ -0,0 +1,201 @@ +# Tutorial 1.2: Introduction to Unit Testing + +**Objective:** To introduce unit testing to the C++ project from Tutorial 1.1. This tutorial will cover adding a testing framework (`googletest`), creating a simple class, writing tests for that class, and integrating the tests into the CMake build system for easy execution within VSCode. + +--- + +## 1. Prerequisites + +* A completed and working project from "Tutorial 1.1: Your First Modern C++ Project". +* `vcpkg` installed and configured as per Tutorial 1.1. + +--- + +## 2. Installing the Testing Framework + +We will use `googletest`, a popular and powerful testing framework for C++. + +Just like with `spdlog`, we use `vcpkg` to install it. + +```bash +# Use the vcpkg executable to install the library +# Replace /path/to/vcpkg with your actual vcpkg path +/home/YOUR_USERNAME/dev/tools/vcpkg/vcpkg install gtest +``` +*Note: The package name is `gtest` for `googletest`.* + +--- + +## 3. Refactoring the Project Structure + +To keep our project organized, we'll separate our main application code from the test code. The new structure inside `tutorial-1` will look like this: +``` +tutorial-1/ +├── CMakeLists.txt +├── src/ +│ ├── calculator.h +│ ├── calculator.cpp +│ └── main.cpp +└── test/ + └── test_calculator.cpp +``` +The previous steps in this session have already created this structure for you. + +--- + +## 4. Creating a Class to Test + +We need some logic to test. We've created a simple `Calculator` class. + +**File:** `tutorial-1/src/calculator.h` +```cpp +#ifndef CALCULATOR_H +#define CALCULATOR_H + +class Calculator { +public: + int add(int a, int b); +}; + +#endif // CALCULATOR_H +``` + +**File:** `tutorial-1/src/calculator.cpp` +```cpp +#include "calculator.h" + +int Calculator::add(int a, int b) { + return a + b; +} +``` + +We also updated `main.cpp` to use this new class. + +**File:** `tutorial-1/src/main.cpp` (Updated) +```cpp +#include +#include "spdlog/spdlog.h" +#include "calculator.h" + +int main() { + spdlog::info("Hello, Modern C++! Initializing trading strategy..."); + + Calculator calc; + int result = calc.add(40, 2); + + spdlog::info("The result of 40 + 2 is: {}", result); + + std::cout << "Check your terminal for spdlog output!" << std::endl; + + return 0; +} +``` + +--- + +## 5. Writing the Unit Tests + +Now, we'll write our first test in the `test` directory. + +**File:** `tutorial-1/test/test_calculator.cpp` +```cpp +#include +#include "../src/calculator.h" // Include the header for the class we are testing + +// Test fixture for Calculator class +class CalculatorTest : public ::testing::Test { +protected: + Calculator calc; +}; + +// Test case for the add method +TEST_F(CalculatorTest, Add) { + EXPECT_EQ(calc.add(2, 2), 4); + EXPECT_EQ(calc.add(-1, 1), 0); + EXPECT_EQ(calc.add(-5, -5), -10); +} + +// Another test case for the add method for good measure +TEST_F(CalculatorTest, AddWithZero) { + EXPECT_EQ(calc.add(0, 5), 5); + EXPECT_EQ(calc.add(5, 0), 5); + EXPECT_EQ(calc.add(0, 0), 0); +} +``` + +--- + +## 6. Updating the Build System (CMake) + +This is the most critical part. We have updated our `CMakeLists.txt` to build both our main application and our tests as separate executables. + +**File:** `tutorial-1/CMakeLists.txt` (Updated) +```cmake +cmake_minimum_required(VERSION 3.15) +project(Tutorial1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Find dependencies +find_package(spdlog CONFIG REQUIRED) +find_package(GTest CONFIG REQUIRED) + +# Create a library for our application code +# This allows us to share the code between the main app and the tests +add_library(MyLib src/calculator.cpp src/calculator.h) +target_include_directories(MyLib PUBLIC src) + +# Define our main executable +add_executable(App src/main.cpp) + +# Link our App against spdlog and our library +target_link_libraries(App PRIVATE spdlog::spdlog MyLib) + +# Enable testing with CTest (CMake's testing framework) +enable_testing() + +# Define the test executable +add_executable(RunTests test/test_calculator.cpp) + +# Link our test executable against GTest and our library +target_link_libraries(RunTests PRIVATE GTest::GTest GTest::Main MyLib) + +# Add the test to CTest +include(GoogleTest) +gtest_add_tests(TARGET RunTests) +``` + +--- + +## 7. Building and Running Tests in VSCode + +1. **Install `gtest`:** Make sure you have installed `gtest` using `vcpkg` as described in step 2. +2. **Configure CMake:** Run `CMake: Configure` from the command palette (Ctrl+Shift+P). It should detect the changes and find `gtest`. +3. **Build:** Click the **Build** button in the status bar. This will now build `App` and `RunTests`. +4. **Run Tests:** The "CMake Tools" extension provides a "Test Explorer" view in VSCode. + * Open the Test Explorer from the side bar (the icon looks like a beaker). + * You should see your test suite (`CalculatorTest`) and the individual tests. + * Click the "play" button at the top of the Test Explorer to run all tests. + * You can also run individual tests. The results will be shown directly in the UI. + +--- + +**Congratulations!** You have now added unit testing to your project. This is a crucial skill for writing robust and maintainable C++ applications. You've learned how to: +* Add a testing library (`googletest`) with `vcpkg`. +* Structure your project to separate app code from test code. +* Create a shared library and multiple executables with CMake. +* Write and run unit tests using the VSCode Test Explorer. + + +## Feedback and Questions + +1. The line ```target_link_libraries(RunTests PRIVATE GTest::GTest GTest::Main MyLib)``` caused cmake compilation error, I changed to +```target_link_libraries(RunTests PRIVATE GTest::gtest_main MyLib)``` +I looked up documentation for this. + +2. Are there alternative ways to install dependencies other the through vcpkg? For example would FetchContent work (https://cmake.org/cmake/help/latest/module/FetchContent.html)? + +3.Interestingly, in vscode, the line ```#include ``` i was curious where the files as located - as i had not specified where it is other the download gtest in a separate process via vcpkg. when in vscode i hovered and clicked on go to definition it went to the location. curious how vscode knows this information. + +4.I was interested to debug unit tests individually and managed to do this by following https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/debug-launch.md#debugging-tests diff --git a/cplusplus/geminitutorial/tutorial2/.vscode/settings.json b/cplusplus/geminitutorial/tutorial2/.vscode/settings.json new file mode 100644 index 0000000..34b3506 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cmake.sourceDirectory": "/home/ys/code/cplusplus/GeminiTutorial/tutorial-2", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=/home/ys/code/cplusplus/vcpkg/scripts/buildsystems/vcpkg.cmake" + ] +} \ No newline at end of file diff --git a/cplusplus/geminitutorial/tutorial2/CMakeLists.txt b/cplusplus/geminitutorial/tutorial2/CMakeLists.txt new file mode 100644 index 0000000..bf11a89 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.15) +project(Tutorial2 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + + + +# Find dependencies + +find_package(spdlog CONFIG REQUIRED) + + + +# Create a library for our application code + +add_library(MyLib src/StockData_Old.cpp src/StockData_Modern.cpp src/CsvParser.cpp) + +target_include_directories(MyLib PUBLIC src) + + + +# Define our main executable + +add_executable(App src/main.cpp) + + + +# Link our App against spdlog and our library + +target_link_libraries(App PRIVATE spdlog::spdlog MyLib) diff --git a/cplusplus/geminitutorial/tutorial2/src/CsvParser.cpp b/cplusplus/geminitutorial/tutorial2/src/CsvParser.cpp new file mode 100644 index 0000000..2faf97c --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/CsvParser.cpp @@ -0,0 +1,73 @@ +#include "CsvParser.h" +#include +#include +#include +#include +#include // For std::remove_if + +namespace CsvParser { + +TickData parseTickCsvLine(std::string_view line) { + TickData tick; + std::string s_line(line); // Convert string_view to string for stringstream + std::stringstream ss(s_line); + std::string segment; + std::vector seglist; + + while(std::getline(ss, segment, ',')) { + seglist.push_back(segment); + } + + if (seglist.size() != 3) { + throw std::runtime_error("CSV line does not have 3 segments: " + std::string(line)); + } + + // Parse timestamp (simplified for now, assumes epoch seconds) + // In a real scenario, this would involve more robust date/time parsing + try { + long long timestamp_sec = std::stoll(seglist[0]); + tick.timestamp = std::chrono::system_clock::from_time_t(timestamp_sec); + } catch (const std::exception& e) { + throw std::runtime_error("Failed to parse timestamp: " + seglist[0] + " - " + e.what()); + } + + // Parse price + try { + tick.price = std::stod(seglist[1]); + } catch (const std::exception& e) { + throw std::runtime_error("Failed to parse price: " + seglist[1] + " - " + e.what()); + } + + // Parse volume + try { + tick.volume = std::stol(seglist[2]); + } catch (const std::exception& e) { + throw std::runtime_error("Failed to parse volume: " + seglist[2] + " - " + e.what()); + } + + return tick; +} + +std::vector parseTickCsvFile(std::string_view filename) +{ + std::vector ticks; + std::ifstream file(std::string{filename}); // Convert string_view to string for ifstream + + if (!file.is_open()) { + throw std::runtime_error("Could not open file: " + std::string(filename)); + } + + std::string line; + while (std::getline(file, line)) { + if (line.empty()) continue; // Skip empty lines + try { + ticks.push_back(parseTickCsvLine(line)); + } catch (const std::runtime_error& e) { + std::cerr << "Error parsing line: \"" << line << "\" - " << e.what() << std::endl; + // Depending on requirements, could rethrow or continue + } + } + return ticks; +} + +} // namespace CsvParser diff --git a/cplusplus/geminitutorial/tutorial2/src/CsvParser.h b/cplusplus/geminitutorial/tutorial2/src/CsvParser.h new file mode 100644 index 0000000..b7e7f7d --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/CsvParser.h @@ -0,0 +1,11 @@ +#pragma once + +#include "TickData.h" +#include +#include +#include // For std::string_view + +namespace CsvParser { + TickData parseTickCsvLine(std::string_view line); + std::vector parseTickCsvFile(std::string_view filename); +} // namespace CsvParser diff --git a/cplusplus/geminitutorial/tutorial2/src/StockData_Modern.cpp b/cplusplus/geminitutorial/tutorial2/src/StockData_Modern.cpp new file mode 100644 index 0000000..f822756 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/StockData_Modern.cpp @@ -0,0 +1,9 @@ +#include "StockData_Modern.h" + +// Constructor: Initialize the vector with a given size +StockData_Modern::StockData_Modern(size_t size) : data_(size) {} + +// Public method to access data (with bounds checking provided by std::vector::at) +double& StockData_Modern::at(size_t index) { + return data_.at(index); +} diff --git a/cplusplus/geminitutorial/tutorial2/src/StockData_Modern.h b/cplusplus/geminitutorial/tutorial2/src/StockData_Modern.h new file mode 100644 index 0000000..b92add9 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/StockData_Modern.h @@ -0,0 +1,19 @@ +#pragma once +#include // For size_t + +#include + +class StockData_Modern { +public: + // Constructor + StockData_Modern(size_t size); + + // No Copy Constructor, Copy Assignment, or Destructor needed! + // The compiler-generated versions work perfectly because `std::vector` handles itself. + + // Public method to access data + double& at(size_t index); + +private: + std::vector data_; +}; diff --git a/cplusplus/geminitutorial/tutorial2/src/StockData_Old.cpp b/cplusplus/geminitutorial/tutorial2/src/StockData_Old.cpp new file mode 100644 index 0000000..286aab9 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/StockData_Old.cpp @@ -0,0 +1,37 @@ +#include "StockData_Old.h" +#include // For std::copy + +// Constructor: Allocate memory for the array +StockData_Old::StockData_Old(size_t size) : size_(size) { + data_ = new double[size_]; +} + +// Destructor: Free the allocated memory +StockData_Old::~StockData_Old() { + delete[] data_; +} + +// Copy Constructor: Perform a deep copy +StockData_Old::StockData_Old(const StockData_Old& other) : size_(other.size_) { + data_ = new double[size_]; + std::copy(other.data_, other.data_ + size_, data_); +} + +// Copy Assignment Operator: Handle self-assignment and perform a deep copy +StockData_Old& StockData_Old::operator=(const StockData_Old& other) { + if (this != &other) { // Protect against self-assignment + // Free the old memory + delete[] data_; + + // Allocate new memory and copy data + size_ = other.size_; + data_ = new double[size_]; + std::copy(other.data_, other.data_ + size_, data_); + } + return *this; +} + +// Public method to access data (no bounds checking for simplicity) +double& StockData_Old::at(size_t index) { + return data_[index]; +} diff --git a/cplusplus/geminitutorial/tutorial2/src/StockData_Old.h b/cplusplus/geminitutorial/tutorial2/src/StockData_Old.h new file mode 100644 index 0000000..f89812f --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/StockData_Old.h @@ -0,0 +1,25 @@ +#pragma once // Use modern include guard + +#include // For size_t + +class StockData_Old { +public: + // Constructor + StockData_Old(size_t size); + + // Copy Constructor (Rule 1 of 3) + StockData_Old(const StockData_Old& other); + + // Copy Assignment Operator (Rule 2 of 3) + StockData_Old& operator=(const StockData_Old& other); + + // Destructor (Rule 3 of 3) + ~StockData_Old(); + + // Public method to access data + double& at(size_t index); + +private: + double* data_; + size_t size_; +}; diff --git a/cplusplus/geminitutorial/tutorial2/src/TickData.h b/cplusplus/geminitutorial/tutorial2/src/TickData.h new file mode 100644 index 0000000..99f1929 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/TickData.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include // For std::ostringstream + +struct TickData { + std::chrono::system_clock::time_point timestamp; + double price; + long volume; + + // Optional: for easy printing/debugging + std::string toString() const { + std::ostringstream oss; + // Convert timestamp to a readable format (simple example) + std::time_t time = std::chrono::system_clock::to_time_t(timestamp); + std::string time_str = std::ctime(&time); + time_str.pop_back(); // Remove trailing newline + + oss << "Timestamp: " << time_str + << ", Price: " << price + << ", Volume: " << volume; + return oss.str(); + } +}; diff --git a/cplusplus/geminitutorial/tutorial2/src/Trade.h b/cplusplus/geminitutorial/tutorial2/src/Trade.h new file mode 100644 index 0000000..052c1e5 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/Trade.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include "spdlog/spdlog.h" + + +class Trade { +public: + Trade(const std::string& instrument, double price) + : instrument_(instrument), price_(price) { + spdlog::info("Trade constructor: {} @ {}", instrument_, price_); + } + + ~Trade() { + spdlog::info("Trade destructor: {} @ {}", instrument_, price_); + } + + void print() const { + spdlog::info("Executing trade: {} for ${}", instrument_, price_); + } + +private: + std::string instrument_; + double price_; +}; diff --git a/cplusplus/geminitutorial/tutorial2/src/main.cpp b/cplusplus/geminitutorial/tutorial2/src/main.cpp new file mode 100644 index 0000000..30047f9 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/src/main.cpp @@ -0,0 +1,202 @@ +#include "spdlog/spdlog.h" +#include "StockData_Old.h" +#include "StockData_Modern.h" +#include "Trade.h" +#include "TickData.h" +#include "CsvParser.h" + +#include // For smart pointers +#include // For std::cout, std::cerr +#include // For std::vector +#include // For std::accumulate +#include // For std::max_element, std::for_each, std::count_if +#include // For std::map (instead of unordered_map for simplicity in example) +#include // For std::string_view +#include // For std::ofstream + +// --- Existing Tutorial 2.1 Demonstrations --- + +void demonstrate_old_way() { + spdlog::info("--- Demonstrating the Old Way (Manual Memory Management) ---"); + StockData_Old prices(5); + for (size_t i = 0; i < 5; ++i) { + prices.at(i) = 100.0 + i; + } + + spdlog::info("Copied prices_copy1(prices)"); + StockData_Old prices_copy1(prices); // Copy constructor + prices_copy1.at(0) = 999.0; + + spdlog::info("prices.at(0) = {}", prices.at(0)); + spdlog::info("prices_copy1.at(0) = {}", prices_copy1.at(0)); + + spdlog::info("Copied prices_copy2 = prices"); + StockData_Old prices_copy2(1); + prices_copy2 = prices; // Copy assignment + prices_copy2.at(1) = 888.0; + + spdlog::info("prices.at(1) = {}", prices.at(1)); + spdlog::info("prices_copy2.at(1) = {}", prices_copy2.at(1)); + + spdlog::info("--- Leaving scope for Old Way demo ---"); +} + +void demonstrate_modern_way() { + spdlog::info("--- Demonstrating the Modern Way (RAII with std::vector) ---"); + StockData_Modern prices(5); + for (size_t i = 0; i < 5; ++i) { + prices.at(i) = 100.0 + i; + } + + spdlog::info("Copied prices_copy1(prices)"); + StockData_Modern prices_copy1(prices); // Copy constructor (compiler-generated) + prices_copy1.at(0) = 999.0; + + spdlog::info("prices.at(0) = {}", prices.at(0)); + spdlog::info("prices_copy1.at(0) = {}", prices_copy1.at(0)); + + spdlog::info("Copied prices_copy2 = prices"); + StockData_Modern prices_copy2(1); + prices_copy2 = prices; // Copy assignment (compiler-generated) + prices_copy2.at(1) = 888.0; + + spdlog::info("prices.at(1) = {}", prices.at(1)); + spdlog::info("prices_copy2.at(1) = {}", prices_copy2.at(1)); + spdlog::info("--- Leaving scope for Modern Way demo ---"); +} + +void demonstrate_smart_pointers() { + spdlog::info("--- Demonstrating Smart Pointers ---"); + + // Demonstrate unique_ptr for exclusive ownership + { + spdlog::info("Creating a unique_ptr-managed Trade"); + auto unique_trade = std::make_unique("AAPL", 150.0); + unique_trade->print(); + // unique_trade is automatically destroyed when this scope ends + } // ~Trade() is called here + + // Demonstrate shared_ptr for shared ownership + { + spdlog::info("Creating a shared_ptr-managed Trade"); + std::shared_ptr shared_trade1; + { + auto shared_trade2 = std::make_shared("GOOG", 2800.0); + shared_trade1 = shared_trade2; // Both pointers now share ownership + spdlog::info("shared_ptr use_count: {}", shared_trade1.use_count()); + shared_trade2->print(); + } // shared_trade2 goes out of scope, but the object is not destroyed + + spdlog::info("shared_ptr use_count after inner scope: {}", shared_trade1.use_count()); + shared_trade1->print(); + // shared_trade1 is automatically destroyed when this scope ends + } // ~Trade() is called here + spdlog::info("--- Leaving scope for Smart Pointers demo ---"); +} + +// --- New Tutorial 2.2 Demonstrations --- + +void generate_mock_csv_file(std::string_view filename, int num_lines) { + spdlog::info("Generating mock CSV file: {}", std::string(filename)); + std::ofstream ofs(std::string{filename}); + if (!ofs.is_open()) { + throw std::runtime_error("Could not create mock CSV file."); + } + + for (int i = 0; i < num_lines; ++i) { + long long timestamp = std::chrono::system_clock::now().time_since_epoch().count() / 1000000000LL + i; + double price = 100.0 + (i * 0.5); + long volume = 100 + (i * 10); + ofs << timestamp << "," << price << "," << volume << "\n"; + } + ofs.close(); +} + + +void demonstrate_stl_containers_algorithms() { + spdlog::info("--- Demonstrating Modern STL Containers & Algorithms (Tutorial 2.2) ---"); + + const std::string_view csv_filename = "mock_tick_data.csv"; + generate_mock_csv_file(csv_filename, 10); + + std::vector ticks; + try { + ticks = CsvParser::parseTickCsvFile(csv_filename); + spdlog::info("Successfully parsed {} ticks.", ticks.size()); + } catch (const std::runtime_error& e) { + spdlog::error("Error parsing CSV file: {}", e.what()); + return; + } + + // Example 1: Find the highest price + auto max_price_it = std::max_element(ticks.begin(), ticks.end(), + [](const TickData& a, const TickData& b) { + return a.price < b.price; + }); + if (max_price_it != ticks.end()) { + spdlog::info("Highest price found: {}", max_price_it->price); + } + + // Example 2: Calculate total volume + long total_volume = std::accumulate(ticks.begin(), ticks.end(), 0LL, + [](long sum, const TickData& tick) { + return sum + tick.volume; + }); + spdlog::info("Total volume: {}", total_volume); + + // Example 3: Filter ticks above a certain price (e.g., > 102.0) + std::vector high_price_ticks; + std::copy_if(ticks.begin(), ticks.end(), std::back_inserter(high_price_ticks), + [](const TickData& tick) { + return tick.price > 102.0; + }); + spdlog::info("Number of ticks with price > 102.0: {}", high_price_ticks.size()); + // std::for_each(high_price_ticks.begin(), high_price_ticks.end(), + // [](const TickData& tick) { spdlog::info(" {}", tick.toString()); }); + + // Example 4: Average price using a lambda + double sum_prices = 0.0; + std::for_each(ticks.begin(), ticks.end(), + [&sum_prices](const TickData& tick) { + sum_prices += tick.price; + }); + if (!ticks.empty()) { + spdlog::info("Average price: {}", sum_prices / ticks.size()); + } + + // Example 5: Aggregate volume by second (using std::map for simplicity) + // For high performance, a custom hash map or a more direct time-series approach would be used. + std::map volume_by_second; + for (const auto& tick : ticks) { + long long sec = std::chrono::duration_cast(tick.timestamp.time_since_epoch()).count(); + volume_by_second[sec] += tick.volume; + } + + spdlog::info("Volume by second (first 3 entries):"); + int count = 0; + for (const auto& entry : volume_by_second) { + if (count >= 3) break; + spdlog::info(" Timestamp (sec): {}, Volume: {}", entry.first, entry.second); + count++; + } + + spdlog::info("--- Leaving scope for STL Containers & Algorithms demo ---"); +} + + +int main() { + spdlog::set_level(spdlog::level::info); + spdlog::info("Starting Tutorial 2: Core Language, Libraries, and Concepts"); + + demonstrate_old_way(); + std::cout << "\n"; + demonstrate_modern_way(); + std::cout << "\n"; + demonstrate_smart_pointers(); + std::cout << "\n"; + demonstrate_stl_containers_algorithms(); + + + spdlog::info("Tutorial 2 finished."); + return 0; +} \ No newline at end of file diff --git a/cplusplus/geminitutorial/tutorial2/tutorial-2.1-plan.md b/cplusplus/geminitutorial/tutorial2/tutorial-2.1-plan.md new file mode 100644 index 0000000..f167ede --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/tutorial-2.1-plan.md @@ -0,0 +1,109 @@ +# Tutorial 2.1 Plan: Resource Management & The Rule of Zero + +**Objective:** To master modern C++ resource management techniques, moving away from manual memory handling (`new`/`delete`) to the robust RAII (Resource Acquisition Is Initialization) idiom. This tutorial will demonstrate the "Rule of Zero" by refactoring a C++98-style class that requires manual memory management into a modern, safer equivalent using standard library containers and smart pointers. + +--- + +## 1. Project Setup + +To keep our tutorials organized, we will create a new directory for this lesson. + +1. **Create a `tutorial-2` directory:** Inside the `GeminiTutorial` project root. +2. **Copy Configuration:** Copy the `CMakeLists.txt` and the `.vscode` directory from `tutorial-1` into the new `tutorial-2` directory. This preserves our build and debug configurations. +3. **Update `CMakeLists.txt`:** Modify the `project()` name at the top of `tutorial-2/CMakeLists.txt` from `Tutorial1` to `Tutorial2`. + +--- + +## 2. The "Old Way": Manual Memory Management (The Rule of Three/Five) + +First, we'll create a class that manually manages a dynamic array of doubles. This will highlight the complexity and risks of the C++98 approach. + +**File:** `tutorial-2/src/StockData_Old.h` +```cpp +#pragma once // Use modern include guard + +#include // For size_t + +class StockData_Old { +public: + // Constructor + StockData_Old(size_t size); + + // Copy Constructor (Rule 1 of 3) + StockData_Old(const StockData_Old& other); + + // Copy Assignment Operator (Rule 2 of 3) + StockData_Old& operator=(const StockData_Old& other); + + // Destructor (Rule 3 of 3) + ~StockData_Old(); + + // Public method to access data + double& at(size_t index); + +private: + double* data_; + size_t size_; +}; +``` +We will also create the corresponding `.cpp` file to implement these special member functions, demonstrating the need for deep copies and manual cleanup. + +--- + +## 3. The "Modern Way": Automatic Resource Management (The Rule of Zero) + +Next, we will create a modern equivalent that leverages `std::vector`. This class will achieve the same functionality with significantly less code and greater safety. + +**File:** `tutorial-2/src/StockData_Modern.h` +```cpp +#pragma once + +#include + +class StockData_Modern { +public: + // Constructor + StockData_Modern(size_t size); + + // No Copy Constructor, Copy Assignment, or Destructor needed! + // The compiler-generated versions work perfectly because `std::vector` handles itself. + + // Public method to access data + double& at(size_t index); + +private: + std::vector data_; +}; +``` +This class adheres to the **Rule of Zero**, as it owns its resources through a standard library container and requires no custom resource management code. + +--- + +## 4. Introducing Smart Pointers for Single Object Ownership + +While containers are for sequences of objects, smart pointers manage the lifetime of a single dynamically allocated object. + +1. **`std::unique_ptr`:** Represents exclusive ownership. The object is destroyed automatically when the `unique_ptr` goes out of scope. +2. **`std::shared_ptr`:** Represents shared ownership. The object is destroyed only when the last `shared_ptr` pointing to it is destroyed. + +We will create a simple `Trade` class and a `main.cpp` to demonstrate creating and managing `Trade` objects on the heap using both `std::unique_ptr` and `std::shared_ptr`. + +--- + +## 5. Updating the Build System and Main Application + +We will modify `tutorial-2/CMakeLists.txt` to include all our new source files (`.cpp` files for `StockData_Old`, `StockData_Modern`, and the new `main.cpp`). + +The `main.cpp` will first use `StockData_Old` to illustrate its usage (and potential pitfalls), then use `StockData_Modern` to show the simplicity and safety of the modern approach, and finally demonstrate the usage of smart pointers. + +--- + +## 6. Summary and Key Takeaways + +This tutorial will provide hands-on experience with the core principles of modern C++ resource management: +* **RAII:** Let objects manage resources. Acquisition is in the constructor, release is in the destructor. +* **Rule of Zero:** By using standard library classes like `std::vector`, `std::string`, `std::unique_ptr`, and `std::shared_ptr` to handle resource ownership, your own classes often don't need any custom destructor, copy/move constructors, or assignment operators. +* **Expressing Ownership:** Choose the right tool for the job: + * `std::vector` for owning a dynamic array of elements. + * `std::unique_ptr` for exclusive ownership of a single heap-allocated object. + * `std::shared_ptr` for shared ownership of a single heap-allocated object. diff --git a/cplusplus/geminitutorial/tutorial2/tutorial-2.2-followup.md b/cplusplus/geminitutorial/tutorial2/tutorial-2.2-followup.md new file mode 100644 index 0000000..2271573 --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/tutorial-2.2-followup.md @@ -0,0 +1,10 @@ +Take Aways: + +1. std::string_view: manipulation of strings without the costs of ownership: + i. copying and storing large string objects + implemented as an type storing the first element and lenght of string + see [link](https://stackoverflow.com/questions/20803826/what-is-string-view) + +2. Explain sync pattern or idiom in relation to string_view +3. clang-tidy static checking -how does it work? + diff --git a/cplusplus/geminitutorial/tutorial2/tutorial-2.2-plan.md b/cplusplus/geminitutorial/tutorial2/tutorial-2.2-plan.md new file mode 100644 index 0000000..813115e --- /dev/null +++ b/cplusplus/geminitutorial/tutorial2/tutorial-2.2-plan.md @@ -0,0 +1,83 @@ +# Tutorial 2.2 Plan: Modern STL Containers & Algorithms + +**Objective:** Use the workhorse containers and algorithms with a focus on performance. The project involves parsing mock CSV tick data using algorithms and lambdas to perform queries. + +--- + +## 1. Project Setup + +We will continue working within the `tutorial-2` directory. No new directory creation is needed. + +## 2. Defining Tick Data Structure + +We'll define a simple struct to represent a tick, containing a timestamp, price, and volume. + +**File:** `tutorial-2/src/TickData.h` +```cpp +#pragma once + +#include +#include + +struct TickData { + std::chrono::system_clock::time_point timestamp; + double price; + long volume; + + // Optional: for easy printing/debugging + std::string toString() const; +}; +``` + +## 3. CSV Parsing Utility + +We'll implement a function to parse a single line of CSV data into a `TickData` object. This will involve string manipulation and conversion. `std::string_view` will be crucial here for zero-copy parsing. + +**File:** `tutorial-2/src/CsvParser.h` +```cpp +#pragma once + +#include "TickData.h" +#include +#include + +namespace CsvParser { + TickData parseTickCsvLine(std::string_view line); + std::vector parseTickCsvFile(std::string_view filename); +} // namespace CsvParser +``` + +**File:** `tutorial-2/src/CsvParser.cpp` +```cpp +#include "CsvParser.h" +#include +#include +#include +#include // For error reporting + +// Implement parseTickCsvLine and parseTickCsvFile +``` + +## 4. Main Application: Parsing and Querying + +In `tutorial-2/src/main.cpp`, we will: +1. Generate some mock CSV tick data (or read from a static file). +2. Use `CsvParser::parseTickCsvFile` to load the data into a `std::vector`. +3. Perform various queries using modern STL algorithms and lambdas: + * Find the highest price. + * Calculate the total volume. + * Filter ticks above a certain price. + * Find the average price within a time range. + * Use `std::unordered_map` to aggregate volume by some key (e.g., minute of the hour). + +## 5. Updating the Build System + +Modify `tutorial-2/CMakeLists.txt` to include `TickData.cpp` and `CsvParser.cpp` (if needed, `TickData` might just be a header). Ensure proper linking. + +## 6. Summary and Key Takeaways + +This tutorial will provide hands-on experience with: +* Efficient string handling using `std::string_view`. +* Storing structured data in `std::vector`. +* Performing data transformations and queries using STL algorithms and lambdas. +* Using `std::unordered_map` for fast lookups and aggregations.