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
17 changes: 13 additions & 4 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ on:
- "include/**"
- "src/**"
- "test/**"
- "cmake/**"
- "Makefile"
- "CMakePresets.json"
- "CMakeLists.txt"
- ".github/workflows/linux.yml"
pull_request:
Expand All @@ -18,6 +21,9 @@ on:
- "include/**"
- "src/**"
- "test/**"
- "cmake/**"
- "Makefile"
- "CMakePresets.json"
- "CMakeLists.txt"
- ".github/workflows/linux.yml"

Expand All @@ -28,8 +34,8 @@ jobs:
fail-fast: false

matrix:
# TODO: sanitizer: [debug, release, asan, usan, tsan]
sanitizer: [debug, release]
# TODO: sanitizer: [debug, release, asan, usan, tsan, lsan, msan]
preset: [debug, release]
compiler: [g++-14, clang++-19]

steps:
Expand All @@ -42,5 +48,8 @@ jobs:
chmod +x llvm.sh
sudo ./llvm.sh 19 all

- name: Linux ${{ matrix.compiler }} ${{ matrix.sanitizer }}
run: CXX=${{ matrix.compiler }} make ${{ matrix.sanitizer }}
- name: Linux ${{ matrix.compiler }} ${{ matrix.preset }}
run: CXX=${{ matrix.compiler }} cmake --workflow --preset ${{ matrix.preset }}

- name: Linux ${{ matrix.compiler }} sanitizer
run: CXX=${{ matrix.compiler }} make all
25 changes: 20 additions & 5 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ on:
- "include/**"
- "src/**"
- "test/**"
- "cmake/**"
- "Makefile"
- "CMakePresets.json"
- "CMakeLists.txt"
- ".github/workflows/macos.yml"
pull_request:
Expand All @@ -18,6 +21,9 @@ on:
- "include/**"
- "src/**"
- "test/**"
- "cmake/**"
- "Makefile"
- "CMakePresets.json"
- "CMakeLists.txt"
- ".github/workflows/macos.yml"

Expand All @@ -28,7 +34,7 @@ jobs:
fail-fast: false

matrix:
sanitizer: [debug, release]
preset: [debug, release]
# TODO: compiler: [g++, clang++-19]
compiler: [g++, clang++-18]

Expand All @@ -49,10 +55,19 @@ jobs:
run: |
brew install llvm@19 || echo ignored

- name: macos clang++-18 ${{ matrix.sanitizer }}
- name: macos clang++-18 ${{ matrix.preset }}
if: startsWith(matrix.compiler, 'clang')
run: CXX=$(brew --prefix llvm@18)/bin/clang++ make ${{ matrix.sanitizer }}
run: CXX=$(brew --prefix llvm@18)/bin/clang++ cmake --workflow --preset ${{ matrix.preset }}

- name: macos g++ ${{ matrix.sanitizer }}
- name: macos clang++-18 sanitizer
if: startsWith(matrix.compiler, 'clang')
run: CXX=$(brew --prefix llvm@18)/bin/clang++ make all

- name: macos g++ ${{ matrix.preset }}
if: startsWith(matrix.compiler, 'g++')
run: CXX=${{ matrix.compiler }} make ${{ matrix.sanitizer }}
run: CXX=${{ matrix.compiler }} cmake --workflow --preset ${{ matrix.preset }}

# TODO: fails with AppleClang 16.0.0 on CI!
# - name: macos g++ sanitizer
# if: startsWith(matrix.compiler, 'g++')
# run: CXX=${{ matrix.compiler }} make all
4 changes: 4 additions & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
- "include/**"
- "src/**"
- "test/**"
- "cmake/**"
- "CMakePresets.json"
- "CMakeLists.txt"
- ".github/workflows/windows.yml"
pull_request:
Expand All @@ -18,6 +20,8 @@ on:
- "include/**"
- "src/**"
- "test/**"
- "cmake/**"
- "CMakePresets.json"
- "CMakeLists.txt"
- ".github/workflows/windows.yml"

Expand Down
36 changes: 25 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
# Makefile
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

SANITIZERS = release debug msan asan usan tsan
MAKEFLAGS+= --no-builtin-rules # Disable the built-in implicit rules.
MAKEFLAGS+= --warn-undefined-variables # Warn when an undefined variable is referenced.

SANITIZERS = release debug usan # TODO: lsan
OS := $(shell /usr/bin/uname)
ifeq ($(OS),Darwin)
SANITIZERS += tsan
endif
ifeq ($(OS),Linux)
SANITIZERS += asan # TODO: msan
endif

.PHONY: default doc run update check ce todo distclean clean codespell clang-tidy build test all format $(SANITIZERS)

COMPILER=system
SYSROOT ?=
TOOLCHAIN ?=

COMPILER=c++
CXX_BASE=$(CXX:$(dir $(CXX))%=%)
ifeq ($(CXX_BASE),g++)
COMPILER=gcc
COMPILER=g++
endif
ifeq ($(CXX_BASE),clang++)
COMPILER=clang
COMPILER=clang++
endif

CXX_FLAGS = -g
Expand All @@ -20,11 +33,10 @@ SOURCEDIR = $(CURDIR)
BUILDROOT = build
BUILD = $(BUILDROOT)/$(SANITIZER)
EXAMPLE = beman.execution26.examples.stop_token
CMAKE_C_COMPILER=$(COMPILER)
CMAKE_CXX_COMPILER=$(COMPILER)

ifeq ($(SANITIZER),release)
CXX_FLAGS = -O3 -pedantic -Wall -Wextra -Werror
CXX_FLAGS = -O3 -Wpedantic -Wall -Wextra -Wshadow # TODO: -Werror
endif
ifeq ($(SANITIZER),debug)
CXX_FLAGS = -g
Expand Down Expand Up @@ -62,11 +74,12 @@ $(SANITIZERS):

build:
@mkdir -p $(BUILD)
cd $(BUILD); CC=$(CXX) cmake $(SOURCEDIR) $(TOOLCHAIN) $(SYSROOT) -DCMAKE_CXX_COMPILER=$(CXX) -DCMAKE_CXX_FLAGS="$(CXX_FLAGS) $(SAN_FLAGS)"
cd $(BUILD); CC=$(CXX) cmake -G Ninja $(SOURCEDIR) $(TOOLCHAIN) $(SYSROOT) -DCMAKE_CXX_COMPILER=$(CXX) -DCMAKE_CXX_FLAGS="$(CXX_FLAGS) $(SAN_FLAGS)"
cmake --build $(BUILD)

test:
cmake --workflow --preset $(SANITIZER)
test: build
# cmake --workflow --preset $(SANITIZER)
ctest --test-dir $(BUILD) --rerun-failed --output-on-failure

ce:
@mkdir -p $(BUILD)
Expand All @@ -83,8 +96,9 @@ check:
< $$h sed -n "/^ *# *include <Beman\//s@.*[</]Beman/\(.*\).hpp>.*@$$from \1@p"; \
done | tsort > /dev/null

build/$(SANITIZER)/compile_commands.json: $(SANITIZER)
clang-tidy: build/$(SANITIZER)/compile_commands.json
run-clang-tidy -p build/$(SANITIZER) tests
run-clang-tidy -p build/$(SANITIZER) tests examples

codespell:
codespell -L statics,snd,copyable,cancelled
Expand All @@ -105,7 +119,7 @@ clean-doc:
$(RM) -r docs/html docs/latex

clean: clean-doc
$(RM) -r $(BUILD)
$(RM) -r $(BUILD)
$(RM) mkerr olderr *~

distclean: clean
Expand Down
15 changes: 9 additions & 6 deletions examples/allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace {
template <std::size_t Size>
struct inline_resource : std::pmr::memory_resource {
const char* name;
inline_resource(const char* name) : name(name) {}
std::byte buffer[Size];
std::byte* next{+this->buffer};
explicit inline_resource(const char* name) : name(name) {}
std::byte buffer[Size]{}; // NOLINT(hicpp-avoid-c-arrays)
std::byte* next{+this->buffer}; // NOLINT(hicpp-no-array-decay)

void* do_allocate(std::size_t size, std::size_t) override {
std::cout << "allocating from=" << this->name << ", size=" << size << "\n";
Expand All @@ -29,6 +29,7 @@ struct inline_resource : std::pmr::memory_resource {
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; }
};

// NOLINTBEGIN(hicpp-special-member-functions)
template <typename Fun>
struct allocator_aware_fun {
using allocator_type = std::pmr::polymorphic_allocator<>;
Expand All @@ -38,10 +39,11 @@ struct allocator_aware_fun {

template <typename F>
requires std::same_as<std::remove_cvref_t<F>, std::remove_cvref_t<Fun>>
allocator_aware_fun(F&& fun) : fun(std::forward<F>(fun)) {}
explicit allocator_aware_fun(F&& fun) : fun(std::forward<F>(fun)) {}
allocator_aware_fun(const allocator_aware_fun& other, allocator_type allocator = {})
: fun(other.fun), allocator(allocator) {}
allocator_aware_fun(allocator_aware_fun&& other) : fun(std::move(other.fun)), allocator(other.allocator) {}
allocator_aware_fun(allocator_aware_fun&& other) noexcept
: fun(std::move(other.fun)), allocator(other.allocator) {}
allocator_aware_fun(allocator_aware_fun&& other, allocator_type allocator)
: fun(std::move(other.fun)), allocator(allocator) {}

Expand All @@ -50,6 +52,7 @@ struct allocator_aware_fun {
return this->fun(this->allocator, std::forward<Args>(args)...);
}
};
// NOLINTEND(hicpp-special-member-functions)
template <typename Fun>
allocator_aware_fun(Fun&& fun) -> allocator_aware_fun<Fun>;

Expand All @@ -60,7 +63,7 @@ struct allocator_env {
} // namespace

auto main() -> int {
int values[] = {1, 2, 3};
int values[] = {1, 2, 3}; // NOLINT(hicpp-avoid-c-arrays)
auto s{ex::just(std::span(values)) | ex::let_value(allocator_aware_fun([](auto alloc, std::span<int> v) {
return ex::just(std::pmr::vector<int>(v.begin(), v.end(), alloc));
})) |
Expand Down
9 changes: 3 additions & 6 deletions examples/playground.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ namespace ex = ::beman::execution26;

int main()
{
auto[result] = ex::sync_wait(
ex::when_all(
ex::just(std::string("hello, ")),
ex::just(std::string("world"))
) | ex::then([](auto s1, auto s2){ return s1 + s2; })
).value_or(std::tuple(std::string("oops")));
auto [result] = ex::sync_wait(ex::when_all(ex::just(std::string("hello, ")), ex::just(std::string("world"))) |
ex::then([](const auto& s1, const auto& s2) { return s1 + s2; }))
.value_or(std::tuple(std::string("oops")));
std::cout << "result='" << result << "'\n";
}
2 changes: 1 addition & 1 deletion examples/sender-demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static_assert(ex::sender_in<just_sender<std::pmr::string>>);

int main() {
auto j = just_sender{std::pmr::string("value")};
auto t = std::move(j) | ex::then([](std::pmr::string v) { return v + " then"; });
auto t = std::move(j) | ex::then([](const std::pmr::string& v) { return v + " then"; });
auto w = ex::when_all(std::move(t));
auto e = ex::detail::write_env(std::move(w),
ex::detail::make_env(ex::get_allocator, std::pmr::polymorphic_allocator<>()));
Expand Down
12 changes: 7 additions & 5 deletions examples/stop_token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ namespace exec = beman::execution26;
// doesn't seem to be readily enabled on MacOS.
// - std::print isn't available everywhere, yet. Let's try a simple
// placeholder.
static ::std::mutex io_lock;
namespace {
::std::mutex io_lock;
void print(std::string_view text, auto&&...) {
std::lock_guard guard(io_lock);
const std::lock_guard guard(io_lock);
::std::cout << text;
}

template <typename Token>
auto active(Token token) -> void {
auto active(const Token& token) -> void {
auto i{0ull};
while (not token.stop_requested()) {
// do work
Expand All @@ -69,9 +70,9 @@ struct stop_callback_for_t {

#ifdef __cpp_lib_latch
template <typename Token>
auto inactive(Token token) -> void {
auto inactive(const Token& token) -> void {
::std::latch latch(1);
stop_callback_for_t cb(token, [&latch] { latch.count_down(); });
const stop_callback_for_t cb(token, [&latch] { latch.count_down(); });

latch.wait();
print("inactive thread done (latch)\n");
Expand All @@ -88,6 +89,7 @@ auto inactive(Token token) -> void {
print("inactive thread done (condition_variable)\n");
}
#endif
} // namespace

auto main() -> int {
exec::stop_source source;
Expand Down
4 changes: 3 additions & 1 deletion examples/stopping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ namespace ex = beman::execution26;

// ----------------------------------------------------------------------------

namespace {
struct env {
ex::inplace_stop_token token;

env(ex::inplace_stop_token token) : token(token) {}
env(ex::inplace_stop_token token) : token(token) {} // NOLINT(hicpp-explicit-conversions)

auto query(const ex::get_stop_token_t&) const noexcept { return this->token; }
};
Expand Down Expand Up @@ -73,6 +74,7 @@ struct receiver {
auto set_error(auto&&) noexcept -> void {}
auto set_stopped() noexcept -> void {}
};
} // namespace

int main() {
ex::inplace_stop_source source;
Expand Down
2 changes: 1 addition & 1 deletion examples/when_all-cancel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ struct eager {
state(R&& r, S&& s) : outer_receiver(std::forward<R>(r)), inner_state() {
inner_state.emplace(std::forward<S>(s), receiver{this});
}
// TODO on next line: bugprone-unchecked-optional-access
auto start() & noexcept -> void { ex::start((*this->inner_state).st); }
};
template <ex::receiver Receiver>
Expand All @@ -127,7 +128,6 @@ auto main() -> int {

ex::inplace_stop_source source{};
auto op{ex::connect(s, receiver{&source})};
(void)op;
std::cout << "start\n";
ex::start(op);
std::cout << "started\n";
Expand Down