Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 120
AlignEscapedNewlines: Left
AlignAfterOpenBracket: AlwaysBreak
#
# Bind * to the type rather than the name.
PointerAlignment: Left
#
# Put function name on separate line from return type.
AlwaysBreakAfterReturnType: All
#
# Put arguments either all on same line or on separate lines.
BinPackArguments: false
#
# Put function parameters on separate lines.
BinPackParameters: false
#
# Open brace goes on new line only when starting a new struct, enum, or func.
BreakBeforeBraces: Mozilla
#
# Don't sort includes in alphabetical order because Windows headers are odd.
SortIncludes: false
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ jobs:
- name: Install build tools
run: |
sudo apt-get update
sudo apt-get install -y build-essential g++ clang
sudo apt-get install -y build-essential g++ clang clang-format

# 3. Build and run all examples dynamically
# 3. Clang-format check
- name: Clang-format Check
run: |
./clang-check.sh *.cpp *.hpp *.c *.h

# 4. Build and run all examples dynamically
- name: Build and Run
run: |
for san in address thread undefined; do
Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Examples include (and will expand to):
* Smart pointers
* [unique-ptr-basics](./unique-ptr-basics/)
* Lock‑free / wait‑free data structures
* Views
* [views-zip-enumerate](./views-zip-enumerate/)
* Atomics and memory ordering
* RAII and ownership patterns
* Performance‑oriented C++ idioms
Expand Down Expand Up @@ -101,7 +103,7 @@ Common compiler settings live in [common.mk](./common.mk):

```make
CXX := g++
CXXFLAGS := -std=c++20 -Wall -Wextra
CXXFLAGS := -std=c++23 -Wall -Wextra
```

Individual examples may extend this, e.g.:
Expand Down Expand Up @@ -131,6 +133,15 @@ make SANITIZE=

---

## Clang Format
The `clang-format` is used to ensure the code format.

```bash
./clang-check.sh *.cpp *.hpp
```

---

## Continuous Integration

GitHub Actions automatically builds all examples on:
Expand All @@ -140,11 +151,16 @@ GitHub Actions automatically builds all examples on:

The CI setup requires **no updates** when new example folders are added.

The CI will perform:
1. `./clang-check.sh *.cpp *.hpp`
2. `make SANITIZE=[address, thread, undefined]`
3. `make run`

---

## Toolchain

* C++20
* C++23
* GNU Make
* GCC / Clang (CI currently uses GCC)
* Linux (Ubuntu)
Expand Down
52 changes: 52 additions & 0 deletions clang-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash
set -euo pipefail

# Supported extensions
supported_ext=("c" "h" "cpp" "hpp")

# Check if a file is supported
is_supported_file() {
local file="$1"
local ext="${file##*.}"
for e in "${supported_ext[@]}"; do
[[ "$ext" == "$e" ]] && return 0
done
return 1
}

# Run clang-format in dry-run mode on a single file
format_file() {
local file="$1"
if is_supported_file "$file"; then
echo "Check Formatting $file"
clang-format --dry-run --Werror "$file"
else
echo "Skipping unsupported file: $file"
fi
}

# Run clang-format on a glob pattern recursively
format_pattern() {
local pattern="$1"
# Find files matching the pattern
find . -type f -iname "$pattern" ! -path "./.git/*" -print0 | while IFS= read -r -d '' file; do
format_file "$file"
done
}

# Main
if [ "$#" -eq 0 ]; then
# Default: format all supported files
for ext in "${supported_ext[@]}"; do
format_pattern "*.$ext"
done
else
for arg in "$@"; do
if [ -f "$arg" ]; then
format_file "$arg"
else
# Treat as a pattern
format_pattern "$arg"
fi
done
fi
2 changes: 1 addition & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ endif
# --------------------------
# Compiler / Linker flags
# --------------------------
CXXFLAGS := -std=c++20 -Wall -Wextra $(OPTFLAGS) $(SAN_FLAGS)
CXXFLAGS := -std=c++23 -Wall -Wextra $(OPTFLAGS) $(SAN_FLAGS)
LDFLAGS := $(SAN_FLAGS)

# --------------------------
Expand Down
2 changes: 1 addition & 1 deletion thread-safe-queue/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ $(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -c $< -o $@

run: $(TARGET)
./$(TARGET)
./$(TARGET) $(ARGS)

clean:
rm -f $(OBJS) $(TARGET)
Expand Down
28 changes: 19 additions & 9 deletions thread-safe-queue/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,53 @@
#include <memory>
#include <thread>

template <typename T>
class ThreadSafeQueue {
public:
template <typename T> class ThreadSafeQueue
{
public:
ThreadSafeQueue() = default;
~ThreadSafeQueue() = default;

void enqueue(T item) {
void
enqueue(T item)
{
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(std::move(item));
cond_var_.notify_one();
}

T dequeue() {
T
dequeue()
{
std::unique_lock<std::mutex> lock(mutex_);
cond_var_.wait(lock, [this]() { return !queue_.empty(); });
T item = queue_.front();
queue_.pop();
return item;
}

bool isEmpty() const {
bool
isEmpty() const
{
std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty();
}

size_t size() const {
size_t
size() const
{
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}

private:
private:
mutable std::mutex mutex_;
std::condition_variable cond_var_;
std::queue<T> queue_;
};

int main() {
int
main()
{
ThreadSafeQueue<int> tsQueue;

// Enqueue some items
Expand Down
2 changes: 1 addition & 1 deletion unique-ptr-basics/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -c $< -o $@

run: $(TARGET)
./$(TARGET)
./$(TARGET) $(ARGS)

clean:
rm -f $(OBJS) $(TARGET)
Expand Down
35 changes: 21 additions & 14 deletions unique-ptr-basics/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,50 @@
#include <memory>
#include <utility>

class Resource {
public:
explicit Resource(int id) : id_(id) {
std::cout << "Resource " << id_ << " acquired\n";
}
class Resource
{
public:
explicit Resource(int id) : id_(id) { std::cout << "Resource " << id_ << " acquired\n"; }

~Resource() {
std::cout << "Resource " << id_ << " released\n";
}
~Resource() { std::cout << "Resource " << id_ << " released\n"; }

void use() const {
void
use() const
{
std::cout << "Using resource " << id_ << "\n";
}

private:
private:
int id_;
};

// Factory function: returns ownership
std::unique_ptr<Resource> make_resource(int id) {
std::unique_ptr<Resource>
make_resource(int id)
{
return std::make_unique<Resource>(id);
}

// Takes ownership explicitly
void consume_resource(std::unique_ptr<Resource> res) {
void
consume_resource(std::unique_ptr<Resource> res)
{
std::cout << "Consuming resource\n";
res->use();
// res is destroyed here
}

// Borrows resource (no ownership transfer)
void inspect_resource(const Resource& res) {
void
inspect_resource(const Resource& res)
{
std::cout << "Inspecting resource\n";
res.use();
}

int main() {
int
main()
{
std::cout << "=== create resource ===\n";
auto r1 = make_resource(1);

Expand Down
25 changes: 25 additions & 0 deletions views-zip-enumerate/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# pull in shared compiler settings
include ../common.mk

# per-example flags
CXXFLAGS += -pthread

TARGET := views-zip-enumerate
SRCS := main.cpp
OBJS := $(SRCS:.cpp=.o)

all: $(TARGET)

$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^

%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@

run: $(TARGET)
./$(TARGET) $(ARGS)

clean:
rm -f $(OBJS) $(TARGET)

.PHONY: all clean run
29 changes: 29 additions & 0 deletions views-zip-enumerate/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <iostream>
#include <string>
#include <ranges>

void
enumerate(std::string_view str)
{
for (const auto& [index, character] : std::views::zip(std::views::iota(0), str)) {
std::cout << index << ": " << character << '\n';
}
}

int
main(int argc, char* argv[])
{
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <string1> <string2> ...\n";
enumerate("default string");
// make pipeline happy
return 0;
}
for (int i = 1; i < argc; ++i) {
std::string_view input = argv[i];
std::cout << "Enumerating string: " << input << '\n';
enumerate(input);
std::cout << "------------------------\n";
}
return 0;
}