Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 5 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,10 @@
"source=cache,target=/home/ubuntu/.cache,type=volume"
],
"workspaceFolder": "/workspace",
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
"remoteUser": "ubuntu"
}
3 changes: 2 additions & 1 deletion examples/.clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ InheritParentConfig: true

Checks: >
-cppcoreguidelines-avoid-magic-numbers,
-readability-magic-numbers
-readability-magic-numbers,
-fuchsia-default-arguments-calls
6 changes: 0 additions & 6 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ add_custom_target(examples)
add_custom_target(run_examples)

# Examples
add_example(example_basic basic.cpp)
run_example(example_basic)

add_example(example_close close.cpp)
run_example(example_close)

add_example(example_move move.cpp)
run_example(example_move)

Expand Down
21 changes: 0 additions & 21 deletions examples/basic.cpp

This file was deleted.

58 changes: 0 additions & 58 deletions examples/close.cpp

This file was deleted.

85 changes: 77 additions & 8 deletions examples/move.cpp
Original file line number Diff line number Diff line change
@@ -1,58 +1,127 @@
#include <msd/channel.hpp>

#include <cstddef>
#include <iostream>
#include <utility>
#include <vector>

class data final {
int value_{};

public:
static std::size_t copies_;
static std::size_t moves_;

data() = default;
explicit data(int value) : value_{value} {}

int get_value() const { return value_; }

data(const data& other) noexcept : value_{other.value_} { std::cout << "copy " << value_ << '\n'; }
data(const data& other) noexcept : value_{other.value_}
{
std::cout << "copy " << value_ << '\n';
++copies_;
}

data& operator=(const data& other)
{
if (this != &other) {
value_ = other.value_;
std::cout << "copy " << value_ << '\n';
++copies_;
}
std::cout << "copy " << value_ << '\n';

return *this;
}

data(data&& other) noexcept : value_{other.value_} { std::cout << "move " << value_ << '\n'; }
data(data&& other) noexcept : value_{other.value_}
{
std::cout << "move " << value_ << '\n';
++moves_;
}

data& operator=(data&& other) noexcept
{
if (this != &other) {
value_ = other.value_;
std::cout << "move " << value_ << '\n';
++moves_;
}

return *this;
}

~data() = default;
virtual ~data() = default;

private:
int value_{};
};

std::size_t data::copies_{};
std::size_t data::moves_{};

int main()
{
msd::channel<data> chan{10};

auto in1 = data{1};
// l-value: will be copied
const auto in1 = data{1};
chan << in1;

// r-value: will be moved
chan << data{2};

// l-value -> std::move -> r-value: will be moved
auto in3 = data{3};
chan << std::move(in3);

for (const auto& out : chan) {
std::vector<int> actual;

// Each value will be moved when read
for (const data& out : chan) {
std::cout << out.get_value() << '\n';

actual.push_back(out.get_value());

if (chan.empty()) {
break;
}
}

const std::vector<int> expected{
1,
2,
3,
};

if (actual != expected) {
std::cerr << "Error: got: ";
for (const int value : actual) {
std::cerr << value << ", ";
}

std::cerr << ", expected: ";
for (const int value : expected) {
std::cerr << value << ", ";
}
std::cerr << '\n';

std::terminate();
}

// 1 copy when in1 was written
constexpr std::size_t expected_copies = 1;

if (data::copies_ != expected_copies) {
std::cerr << "Error: copies: " << data::copies_ << ", expected: " << expected_copies << '\n';
std::terminate();
}

// 1 move when the second value was written
// 1 move when in3 was written
// 3 moves when the 3 values were read
constexpr std::size_t expected_moves = 5;

if (data::moves_ != expected_moves) {
std::cerr << "Error: moves: " << data::moves_ << ", expected: " << expected_moves << '\n';
std::terminate();
}
}
22 changes: 12 additions & 10 deletions examples/streaming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <thread>
#include <vector>

// Spawns multiple producers that send strings into a channel, which are streamed to std::cout from a consumer.

int main()
{
using messages = msd::channel<std::string>;
Expand All @@ -15,7 +17,7 @@ int main()
messages channel{threads};

// Continuously get some data on multiple threads and send it all to a channel
const auto input = [](messages& chan, std::size_t thread, std::chrono::milliseconds pause) {
const auto produce = [](const std::size_t thread, const std::chrono::milliseconds pause, messages& chan) {
thread_local static std::size_t inc = 0U;

while (!chan.closed()) {
Expand All @@ -26,24 +28,24 @@ int main()
}
};

std::vector<std::future<void>> in_futures;
std::vector<std::future<void>> producers;
for (std::size_t i = 0U; i < threads; ++i) {
in_futures.push_back(std::async(input, std::ref(channel), i, std::chrono::milliseconds{500}));
producers.push_back(std::async(produce, i, std::chrono::milliseconds{500}, std::ref(channel)));
}

// Close the channel after some time
const auto timeout = [](messages& chan, std::chrono::milliseconds after) {
const auto close = [](const std::chrono::milliseconds after, messages& chan) {
std::this_thread::sleep_for(after);
chan.close();
};
const auto timeout_future = std::async(timeout, std::ref(channel), std::chrono::milliseconds{3000U});
const auto closer = std::async(close, std::chrono::milliseconds{3000U}, std::ref(channel));

// Stream incoming data to a destination
// Stream incoming messages
std::move(channel.begin(), channel.end(), std::ostream_iterator<std::string>(std::cout, "\n"));

// Wait for other threads
for (auto& future : in_futures) {
future.wait();
// Wait all tasks
for (auto& producer : producers) {
producer.wait();
}
timeout_future.wait();
closer.wait();
}