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
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
# CLion folders
/.idea
/cmake-build-*

/build*
# guided_examples products
/docs/guided_examples/*/build*
/docs/guided_examples/flake.lock

# Avoid adding symlinks
/support/ides/clion/*

# Products of SimoSim
Simo.log
statistics.yaml
Expand Down
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cmake_minimum_required(VERSION 3.31.0)
project(Simo VERSION 0.0.1)
include(CPack)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

option(PORTABLE_BUILD "Be verbose on build and turn warnings into errors for the sake of build portability" ON)
Expand Down Expand Up @@ -199,6 +199,11 @@ target_sources(test_Parameter PRIVATE
tests/parameter/ParameterTest.cc
)

create_unit_test_executable(test_Port)
target_sources(test_Port PRIVATE
tests/port/PortTest.cc
)

create_unit_test_executable(test_Statistics)
target_sources(test_Statistics PRIVATE
tests/statistics/StatisticsTest.cc
Expand Down
11 changes: 8 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@
};

derivationAttributes = {
default = pkgs.clangStdenv.mkDerivation simoBaseAttributes;
clang = pkgs.clangStdenv.mkDerivation simoBaseAttributes;
gcc = pkgs.gccStdenv.mkDerivation simoBaseAttributes;
default = pkgs.clangStdenv.mkDerivation simoBaseAttributes;
clang = pkgs.clangStdenv.mkDerivation simoBaseAttributes;
gcc = pkgs.gccStdenv.mkDerivation simoBaseAttributes;
};
in
{
Expand All @@ -106,11 +106,16 @@
{
inputsFrom = [ derivationAttributes.default ];
packages = with pkgs; [
git
bashInteractive
clang-tools
ast-grep
# For llvm-cov
llvmPackages.llvm
];
shellHook = ''
export SHELL="${pkgs.bashInteractive}/bin/bash"
'';
};
}
);
Expand Down
139 changes: 138 additions & 1 deletion include/Simo/port/Port.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#define SIMO_PORT_HH

#include <expected>
#include <functional>
#include <utility>

#include "Simo/compiler/BoostTypeIndexRuntimeCast.h"
#include "Simo/compiler/Compiler.h"
Expand Down Expand Up @@ -53,6 +55,9 @@ namespace Ports {
template <typename Payload>
class InPort;

template <typename Payload, typename ReturnType>
class CallbackOutPort;

/// Templated port that can send payloads to an InPort of the same type
///
/// Present the payload to the connected port with send and clear that state
Expand Down Expand Up @@ -89,6 +94,19 @@ class SIMO_PUBLIC OutPort : public Port {
std::abort();
}

SEND_OUTCOME send(Payload& payload) {
storage = payload;
switch (state_) {
case PORT_STATE::EMPTY:
state_ = PORT_STATE::FILLED;
return SEND_OUTCOME::NEW;
case PORT_STATE::FILLED:
state_ = PORT_STATE::FILLED;
return SEND_OUTCOME::REPLACED;
}
std::abort();
}

void clear() { state_ = PORT_STATE::EMPTY; }

PORT_STATE state() const { return state_; }
Expand Down Expand Up @@ -132,6 +150,91 @@ class SIMO_PUBLIC InPort : public Port {
OutPort<Payload>* connecting_port = nullptr;
};

/// Templated output port that receives payloads from a CallbackInPort of the
/// same type and invokes a callback for each payload.
template <typename Payload, typename ReturnType>
class SIMO_PUBLIC CallbackInPort : public Port {
public:
friend class CallbackOutPort<Payload, ReturnType>;

using Callback = std::function<ReturnType(Payload)>;

CallbackInPort() = default;
explicit CallbackInPort(Callback callback) : callback_(std::move(callback)) {}

BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(Port)
[[nodiscard]]
bool connect(Port* other) override;

void callback(Callback callback) { callback_ = std::move(callback); }

[[nodiscard]]
bool has_callback() const {
return static_cast<bool>(callback_);
}

protected:
void receive(Payload payload)
requires(std::is_same_v<ReturnType, void>)
{
if (callback_) {
callback_(std::forward<Payload>(payload));
}
}

[[nodiscard]]
std::optional<ReturnType> receive(Payload payload)
requires(!std::is_same_v<ReturnType, void>)
{
if (callback_) {
return callback_(std::forward<Payload>(payload));
}
return std::nullopt;
}

Callback callback_;
};

/// Templated input port that sends payloads to a CallbackOutPort of the same
/// type.
template <typename Payload, typename ReturnType>
class SIMO_PUBLIC CallbackOutPort : public Port {
public:
friend class CallbackInPort<Payload, ReturnType>;
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(Port)
[[nodiscard]]
bool connect(Port* other) override;

[[nodiscard]]
std::optional<ReturnType> send(Payload&& payload) {
if (connecting_port == nullptr) {
return std::nullopt;
}
return connecting_port->receive(std::forward<Payload>(payload));
}

void send(const Payload&& payload)
requires(std::is_same_v<ReturnType, void>)
{
if (connecting_port != nullptr) {
connecting_port->receive(std::forward<Payload>(payload));
}
}

[[nodiscard]]
std::optional<ReturnType> send(const Payload& payload)
requires(!std::is_same_v<ReturnType, void>)
{
if (connecting_port != nullptr) {
return connecting_port->receive(payload);
}
return std::nullopt;
}

protected:
CallbackInPort<Payload, ReturnType>* connecting_port = nullptr;
};

template <typename Payload>
bool OutPort<Payload>::connect(Port* other) {
if (other->get_type_id() != get_type_id<Port>()) {
Expand All @@ -158,6 +261,36 @@ bool InPort<Payload>::connect(Port* other) {
return true;
}

template <typename Payload, typename ReturnType>
bool CallbackOutPort<Payload, ReturnType>::connect(Port* other) {
if (other == nullptr || other->get_type_id() != get_type_id<Port>()) {
return false;
}
auto* other_casted =
boost::typeindex::runtime_cast<CallbackInPort<Payload, ReturnType>*>(
other);
if (other_casted == nullptr) {
return false;
}
connecting_port = other_casted;
return true;
}

template <typename Payload, typename ReturnType>
bool CallbackInPort<Payload, ReturnType>::connect(Port* other) {
if (other == nullptr || other->get_type_id() != get_type_id<Port>()) {
return false;
}
auto* other_casted =
boost::typeindex::runtime_cast<CallbackOutPort<Payload, ReturnType>*>(
other);
if (other_casted == nullptr) {
return false;
}
other_casted->connecting_port = this;
return true;
}

/// Port that can send and receive payloads on separate channels.
/// It can be connected to a BidirectionalPortTyped<InPayload,OutPayload> (note
/// the types are inverted).
Expand All @@ -172,6 +305,10 @@ class SIMO_PUBLIC BidirectionalPortTyped : public Port {
return out_port.send(std::move(payload));
}

OutPort<OutPayload>::SEND_OUTCOME send_out(OutPayload& payload) {
return out_port.send(payload);
}

void clear_out() { out_port.clear(); }

void clear_in() { in_port.clear(); }
Expand Down Expand Up @@ -205,4 +342,4 @@ bool BidirectionalPortTyped<OutPayload, InPayload>::connect(Port* other) {

} // namespace Simo

#endif // SIMO_PORT_HH
#endif // SIMO_PORT_HH
13 changes: 6 additions & 7 deletions support/ides/clion/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# Use Nix packages in CLion

Based on [this](https://gist.github.com/pmenke-de/2fed80213c48c2fe80891678f4fa3b42),
but reworked to use flakes.
From the terminal, open a development environment with `nix develop`.

1. Run `support/ides/clion/setup-symlinks.sh` to expose some nix binaries
2. In `Settings` -> `Build, Execution, Deployment` -> `Toolchains`, create a new toolchain
3. Set CMake executable to `support/ides/clion/nix-cmake.sh` and the other elements of the
toolchain to the symlinks created in step 1.
Inside the development environment, launch CLion.

Note it is important to set the symlink of ctest to be able to run unit-tests from CLion.
On macOS, this can be done with `open -na "CLion.app"`.

One issue is that the integrated terminal may complain about `bash: bind: command not found`
and show escape symbol. The solution is to run `nix develop` in the terminal.
29 changes: 0 additions & 29 deletions support/ides/clion/nix-cmake.sh

This file was deleted.

19 changes: 0 additions & 19 deletions support/ides/clion/nix-run.sh

This file was deleted.

26 changes: 0 additions & 26 deletions support/ides/clion/setup-symlinks.sh

This file was deleted.

2 changes: 2 additions & 0 deletions tests/Simo/MainLoopTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "support/BoostInclude.h"

namespace Simo::Tests {
class TestModule : public Simo::Module {
public:
Simo::InitializationStatus initialize(Simo::Context& ctx,
Expand Down Expand Up @@ -97,3 +98,4 @@ BOOST_AUTO_TEST_CASE(InitializationFailure) {
ss << initialize_success;
BOOST_CHECK_EQUAL(ss.str(), initialization_success_str);
}
} // namespace Simo::Tests
2 changes: 2 additions & 0 deletions tests/Simo/SimulationContextTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "support/BoostInclude.h"

namespace Simo::Tests {
class InitTrackingModule final : public Simo::Module {
public:
Simo::InitializationStatus initialize(
Expand Down Expand Up @@ -263,3 +264,4 @@ BOOST_AUTO_TEST_CASE(ModuleParametersGetSubtreeHitAndMiss) {
auto missing = params.get_subtree("missing");
BOOST_CHECK_EQUAL(missing.has_value(), false);
}
} // namespace Simo::Tests
2 changes: 2 additions & 0 deletions tests/collection/CollectionTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define DYNLIB_EXT "so"
#endif

namespace Simo::Tests {
namespace {
std::filesystem::path collection_library_path() {
// Assuming tests are run from the build folder
Expand Down Expand Up @@ -264,3 +265,4 @@ BOOST_AUTO_TEST_CASE(collection_with_lib_move_assignment_and_self_move) {

BOOST_CHECK_EQUAL(destination.get_collection(), source_collection);
}
} // namespace Simo::Tests
Loading