Skip to content

Onezerozero #55

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 7, 2025
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
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Checks: >
-hicpp-named-parameter,
-readability-named-parameter,
-altera-unroll-loops,
-llvmlibc-inline-function-decl,
-cppcoreguidelines-avoid-const-or-ref-data-members

WarningsAsErrors: "*"

Expand Down
76 changes: 49 additions & 27 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
# https://gist.github.com/NickNaso/0d478f1481686d5bcc868cac06620a60
name: build

on:
push:
branches:
- master
paths-ignore:
- '.vscode/**'
- 'LICENSE'
- 'README.md'
pull_request:
paths-ignore:
- '.vscode/**'
- 'LICENSE'
- 'README.md'
workflow_dispatch:
schedule:
- cron: '0 18 1 * *'

env:
CTEST_OUTPUT_ON_FAILURE: ON
CTEST_PARALLEL_LEVEL: 2

jobs:
build:
test:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}

Expand All @@ -23,65 +32,78 @@ jobs:
name: "Ubuntu Latest GCC (Release)",
os: ubuntu-latest,
build_type: "Release",
coverage: false,
}
- {
name: "Ubuntu 22.04 GCC (Debug)",
os: ubuntu-22.04,
build_type: "Debug",
coverage: true,
}
- {
name: "macOS Latest Clang (Release)",
os: macos-latest,
build_type: "Release",
coverage: false,
}
- {
name: "Windows Latest (Release)",
os: windows-latest,
build_type: "Release",
coverage: false,
}

steps:
- uses: actions/checkout@v4

- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{github.workspace}}/build

- name: Configure CMake
# Use a bash shell so we can use the same syntax for environment variable
# access regardless of the host operating system
shell: bash
working-directory: ${{github.workspace}}/build
# Note the current convention is to use the -S and -B options here to specify source
# and build directories, but this is only available with CMake 3.13 and higher.
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -Dcpp_channel_build_examples=ON -Dcpp_channel_build_tests=ON
run: cmake ${{ github.workspace }} -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -Dcpp_channel_build_examples=ON -Dcpp_channel_build_tests=ON

- name: Build
working-directory: ${{github.workspace}}/build
shell: bash
# Execute the build. You can specify a specific target with "--target <NAME>"
run: cmake --build . --config ${{ matrix.config.build_type }} --target tests

- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{ matrix.config.build_type }} --verbose -R channel_test*

- name: Run examples
working-directory: ${{github.workspace}}/build
run: cmake --build . --config ${{ matrix.config.build_type }} --target examples

coverage:
name: Coverage
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build

- name: Configure CMake
working-directory: ${{github.workspace}}/build
run: cmake ${{ github.workspace }} -DCMAKE_BUILD_TYPE=Debug -Dcpp_channel_build_tests=ON

- name: Build
working-directory: ${{github.workspace}}/build
run: cmake --build . --config Debug --target tests

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -C Debug --verbose -R channel_test11

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
if: matrix.config.coverage == true

- name: Run examples
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --build . --config ${{ matrix.config.build_type }} --target examples
clang-format:
name: Clang Format
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Run Clang Format
run: clang-format --dry-run --Werror $(find include -type f)
7 changes: 3 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
"-Dcpp_channel_build_examples=ON",
"-Dcpp_channel_build_tests=ON"
],
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"clang-tidy.fixOnSave": false,
"clang-tidy.lintOnSave": false,
"editor.formatOnSave": true,
"clang-format.executable": "clang-format",
"clang-format.style": "file",
"editor.defaultFormatter": "xaver.clang-format",
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimFinalNewlines": true
}
17 changes: 10 additions & 7 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
coverage:
precision: 2
round: down
range: "100...100"
status:
project: true
patch: true
changes: true

patch:
default:
target: 96%
threshold: 0%
if_ci_failed: error
project:
default:
target: 97%
threshold: 0%
if_ci_failed: error
ignore:
- 'tests/*'
2 changes: 1 addition & 1 deletion include/msd/blocking_iterator.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2023 Andrei Avram
// Copyright (C) 2020-2025 Andrei Avram

#ifndef MSD_CHANNEL_BLOCKING_ITERATOR_HPP_
#define MSD_CHANNEL_BLOCKING_ITERATOR_HPP_
Expand Down
83 changes: 70 additions & 13 deletions include/msd/channel.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2023 Andrei Avram
// Copyright (C) 2020-2025 Andrei Avram

#ifndef MSD_CHANNEL_HPP_
#define MSD_CHANNEL_HPP_
Expand All @@ -10,7 +10,6 @@
#include <queue>
#include <stdexcept>
#include <type_traits>
#include <utility>

#include "blocking_iterator.hpp"

Expand Down Expand Up @@ -54,7 +53,7 @@ class channel {
*
* @param capacity Number of elements the channel can store before blocking.
*/
explicit constexpr channel(size_type capacity);
explicit constexpr channel(const size_type capacity) : cap_{capacity} {}

/**
* Pushes an element into the channel.
Expand All @@ -75,28 +74,35 @@ class channel {
/**
* Returns the number of elements in the channel.
*/
NODISCARD inline size_type constexpr size() const noexcept;
NODISCARD size_type constexpr size() const noexcept { return size_; }

/**
* Returns true if there are no elements in channel.
*/
NODISCARD inline bool constexpr empty() const noexcept;
NODISCARD bool constexpr empty() const noexcept { return size_ == 0; }

/**
* Closes the channel.
*/
inline void close() noexcept;
inline void close() noexcept
{
{
std::unique_lock<std::mutex> lock{mtx_};
is_closed_.store(true);
}
cnd_.notify_all();
}

/**
* Returns true if the channel is closed.
*/
NODISCARD inline bool closed() const noexcept;
NODISCARD inline bool closed() const noexcept { return is_closed_.load(); }

/**
* Iterator
*/
iterator begin() noexcept;
iterator end() noexcept;
iterator begin() noexcept { return blocking_iterator<channel<T>>{*this}; }
iterator end() noexcept { return blocking_iterator<channel<T>>{*this}; }

/**
* Channel cannot be copied or moved.
Expand All @@ -115,13 +121,64 @@ class channel {
std::condition_variable cnd_;
std::atomic<bool> is_closed_{false};

inline void waitBeforeRead(std::unique_lock<std::mutex>&);
inline void waitBeforeWrite(std::unique_lock<std::mutex>&);
inline void waitBeforeRead(std::unique_lock<std::mutex>& lock)
{
cnd_.wait(lock, [this]() { return !empty() || closed(); });
};

inline void waitBeforeWrite(std::unique_lock<std::mutex>& lock)
{
if (cap_ > 0 && size_ == cap_) {
cnd_.wait(lock, [this]() { return size_ < cap_; });
}
}

friend class blocking_iterator<channel>;
};

} // namespace msd
template <typename T>
channel<typename std::decay<T>::type>& operator<<(channel<typename std::decay<T>::type>& ch, T&& in)
{
{
std::unique_lock<std::mutex> lock{ch.mtx_};
ch.waitBeforeWrite(lock);

if (ch.closed()) {
throw closed_channel{"cannot write on closed channel"};
}

ch.queue_.push(std::forward<T>(in));
++ch.size_;
}

ch.cnd_.notify_one();

return ch;
}

#include "channel.inl"
template <typename T>
channel<T>& operator>>(channel<T>& ch, T& out)
{
{
std::unique_lock<std::mutex> lock{ch.mtx_};
ch.waitBeforeRead(lock);

if (ch.closed() && ch.empty()) {
return ch;
}

if (!ch.empty()) {
out = std::move(ch.queue_.front());
ch.queue_.pop();
--ch.size_;
}
}

ch.cnd_.notify_one();

return ch;
}

} // namespace msd

#endif // MSD_CHANNEL_HPP_
Loading