Skip to content

Commit

Permalink
- Make source C++14 compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
nfogh committed Oct 2, 2023
1 parent ea8baf5 commit c00a96c
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 88 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.21)

# Only set the cxx_standard if it is not set by someone else
if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 14)
endif()

# strongly encouraged to enable this globally to avoid conflicts between
Expand Down
1 change: 1 addition & 0 deletions examples/pubsub/PubSub/PubSub.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "IPubSub.hpp"
#include <cassert>
#include <cstring>
#include <unordered_map>

#include <iostream>

Expand Down
72 changes: 52 additions & 20 deletions examples/pubsub/PubSubMonitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@
#include <tuple>

namespace PubSubMonitoring {
namespace intern {
template<typename TupleT, typename Fn> void for_each_tuple(Fn &&fn, TupleT &&tp)
namespace Intern {
template<typename T, typename FuncT, int... Is> void for_each(FuncT func, T &&arg, std::integer_sequence<int, Is...>)
{
std::apply([&fn](auto &&...args) { (fn(std::forward<decltype(args)>(args)), ...); }, std::forward<TupleT>(tp));
auto unused{ (func(std::get<Is>(arg)), 0)... };
(void)unused;
}
}// namespace intern

template<typename FuncT, typename... Ts> void for_each_in_tuple(FuncT func, std::tuple<Ts...> &args)
{
for_each(func, args, std::make_integer_sequence<int, sizeof...(Ts)>());
}

template<typename FuncT, typename... Ts> void for_each_in_tuple(FuncT func, const std::tuple<Ts...> &args)
{
for_each(func, args, std::make_integer_sequence<int, sizeof...(Ts)>());
}
}// namespace Intern

struct SubscribeAndCheckFunc
{
Expand All @@ -30,42 +41,48 @@ struct SubscribeAndCheckFunc
std::function<void(void)> mCheckFunc;
};

template<typename MessagesT, typename MonitorT> struct PubSubMonitor
template<typename MessagesT, typename MonitorT> struct PubSubMonitorT
{
PubSubMonitor(IPubSub &pubsub, MessagesT messages, MonitorT monitor)
PubSubMonitorT(IPubSub &pubsub, MessagesT messages, MonitorT monitor)
: mPubSub(pubsub), mMessages(std::move(messages)), mMonitor(std::move(monitor))
{
mMonitor.GetOpt().SetCheckFunc([&] { Check(); });
intern::for_each_tuple([&](auto &arg) { mPubSub.Subscribe(arg, [&] { Check(); }); }, mMessages);
Intern::for_each_in_tuple([&](auto &arg) { mPubSub.Subscribe(arg, [&] { Check(); }); }, mMessages);
Check();
}

~PubSubMonitor()
~PubSubMonitorT()
{
intern::for_each_tuple([&](auto &arg) { mPubSub.Unsubscribe(arg); }, mMessages);
Intern::for_each_in_tuple([&](auto &arg) { mPubSub.Unsubscribe(arg); }, mMessages);
}

private:
void Check()
{
std::apply([&](auto &&...args) { mMonitor(std::forward<decltype(args)>(args)...); }, mMessages);
Monitoring::Intern::apply([&](auto &&...args) { mMonitor(std::forward<decltype(args)>(args)...); }, mMessages);
}

IPubSub &mPubSub;
MessagesT mMessages;
MonitorT mMonitor;
};

template<typename MessagesT, typename RequirementsT> struct MonitorWithRequirements
template<typename MessagesT, typename MonitorT>
auto PubSubMonitor(IPubSub &pubsub, MessagesT messages, MonitorT monitor)
{
MonitorWithRequirements(MessagesT messages, IPubSub &pubsub, RequirementsT requirements)
return PubSubMonitorT<MessagesT, MonitorT>(pubsub, std::move(messages), std::move(monitor));
}

template<typename MessagesT, typename RequirementsT> struct MonitorWithRequirementsT
{
MonitorWithRequirementsT(MessagesT messages, IPubSub &pubsub, RequirementsT requirements)
: mMessages(std::move(messages)), mPubSub(pubsub), mRequirements(std::move(requirements))
{}

template<typename... HandlersT> [[nodiscard]] auto Handler(HandlersT &&...handlers)
template<typename... HandlersT> /*[[nodiscard]]*/ auto Handler(HandlersT &&...handlers)
{
auto mergedHandlers = [handlers = std::forward_as_tuple(handlers...)](bool result) {
std::apply([result](auto &&...handlers) { (..., handlers(result)); }, handlers);
Intern::for_each_in_tuple([&](auto &handler) { handler(result); }, handlers);
};
auto subscribeAndCheckFunc = SubscribeAndCheckFunc(mPubSub);
return PubSubMonitor(mPubSub, mMessages, Monitoring::Monitor(mRequirements, mergedHandlers, subscribeAndCheckFunc));
Expand All @@ -77,11 +94,17 @@ template<typename MessagesT, typename RequirementsT> struct MonitorWithRequireme
RequirementsT mRequirements;
};

template<typename MessagesT> struct MonitorWith
template<typename MessagesT, typename RequirementsT>
auto MonitorWithRequirements(MessagesT messages, IPubSub &pubsub, RequirementsT requirements)
{
return MonitorWithRequirementsT<MessagesT, RequirementsT>(std::move(messages), pubsub, std::move(requirements));
}

template<typename MessagesT> struct MonitorWithT
{
MonitorWith(MessagesT messages, IPubSub &pubsub) : mMessages(std::move(messages)), mPubSub(pubsub) {}
MonitorWithT(MessagesT messages, IPubSub &pubsub) : mMessages(std::move(messages)), mPubSub(pubsub) {}

template<typename RequirementsT> [[nodiscard]] auto Require(RequirementsT &&requirements)
template<typename RequirementsT> /*[[nodiscard]]*/ auto Require(RequirementsT &&requirements)
{
return MonitorWithRequirements(mMessages, mPubSub, std::forward<RequirementsT>(requirements));
}
Expand All @@ -91,15 +114,24 @@ template<typename MessagesT> struct MonitorWith
IPubSub &mPubSub;
};

template<typename MessagesT> auto MonitorWith(MessagesT messages, IPubSub &pubsub)
{
return MonitorWithT<MessagesT>(std::move(messages), pubsub);
}

template<typename... MessageT> struct Monitor
template<typename... MessageT> struct MonitorT
{
Monitor(MessageT... messages) : mMessages(messages...) {}
MonitorT(MessageT... messages) : mMessages(std::move(messages)...) {}

[[nodiscard]] auto With(IPubSub &pubsub) { return MonitorWith(mMessages, pubsub); }
/*[[nodiscard]]*/ auto With(IPubSub &pubsub) { return MonitorWith(mMessages, pubsub); }

private:
std::tuple<MessageT...> mMessages;
};

template<typename... MessageT> auto Monitor(MessageT &&...messages)
{
return MonitorT<MessageT...>(std::forward<MessageT>(messages)...);
}

}// namespace PubSubMonitoring
7 changes: 5 additions & 2 deletions examples/pubsub/PubSubMonitorExample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ auto PrintResult()
return [](bool good) { std::cout << std::boolalpha << "Good? " << good << std::endl; };
}

constexpr auto Print = [](bool good) { std::cout << std::boolalpha << "Good? " << good << std::endl; };
auto Print()
{
return [](bool good) { std::cout << std::boolalpha << "Good? " << good << std::endl; };
}

int main()
{
Expand All @@ -31,7 +34,7 @@ int main()

std::cout << "Test min/max: " << std::endl;
auto monitor =
PubSubMonitoring::Monitor(FloatMessage("MySignal")).With(ps).Require(Min(FloatMessage("MyLimit"))).Handler(Print);
PubSubMonitoring::Monitor(FloatMessage("MySignal")).With(ps).Require(Min(FloatMessage("MyLimit"))).Handler(Print());

std::cout << "Setting new limit to 5.0\n";
ps.Publish(FloatMessage(5.0f, "MyLimit"));
Expand Down
31 changes: 30 additions & 1 deletion include/monitoring/conditions/argindex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,41 @@
#include <tuple>

namespace Monitoring {
namespace Intern {
template<typename Fn, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<Fn>>{}, int> = 0>
constexpr decltype(auto) invoke(Fn &&f, Args &&...args) noexcept(
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
return std::mem_fn(f)(std::forward<Args>(args)...);
}

template<typename Fn, typename... Args, std::enable_if_t<!std::is_member_pointer<std::decay_t<Fn>>{}, int> = 0>
constexpr decltype(auto) invoke(Fn &&f, Args &&...args) noexcept(
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
{
return std::forward<Fn>(f)(std::forward<Args>(args)...);
}

template<class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence<I...>)
{
return invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}

template<class F, class Tuple> constexpr decltype(auto) apply(F &&f, Tuple &&t)
{
return apply_impl(std::forward<F>(f),
std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
}// namespace Intern

//@brief Pick out a number of arguments from the supplied arguments
template<size_t... ArgIndices, typename InnerConditionT> auto Args(InnerConditionT innerCondition)
{
auto lamb = [innerCondition = std::move(innerCondition)](auto &&opt, auto &&...args) {
const auto argsTuple = std::forward_as_tuple(args...);
return std::apply(innerCondition,
return Intern::apply(innerCondition,
std::tuple_cat(std::make_tuple(opt), std::forward_as_tuple(std::get<ArgIndices>(std::move(argsTuple))...)));
};
return LogicCallable<decltype(lamb)>(std::move(lamb));
Expand Down
2 changes: 1 addition & 1 deletion include/monitoring/conditions/equals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Monitoring {

template<typename Getter, typename T> auto Equals(Getter getter, std::initializer_list<T> otherVals)
{
auto lamb = [otherVals = std::vector(otherVals), getter = std::move(getter)](const auto &, const T &val) {
auto lamb = [otherVals = std::vector<T>(otherVals), getter = std::move(getter)](const auto &, const T &val) {
return std::any_of(otherVals.cbegin(), otherVals.cend(), [&val, getter = std::move(getter)](const auto &otherVal) {
return getter(val) == getter(otherVal);
});
Expand Down
2 changes: 1 addition & 1 deletion include/monitoring/conditions/field.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ auto Field(FieldT ClassT::*field, InnerConditionT innerCond)
{
auto lamb = [field, innerCond = std::move(innerCond)](
const auto &opt, const auto &arg) { return innerCond(opt, arg.*field); };
return LogicCallable(lamb);
return LogicCallable(std::move(lamb));
};
}// namespace Monitoring
14 changes: 8 additions & 6 deletions include/monitoring/conditions/intern.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once

namespace Monitoring::Intern {
template<typename T> auto Identity()
{
return [](const T &val) { return val; };
}
}// namespace Monitoring::Intern
namespace Monitoring {
namespace Intern {
template<typename T> auto Identity()
{
return [](const T &val) { return val; };
}
}// namespace Intern
}// namespace Monitoring
53 changes: 35 additions & 18 deletions include/monitoring/conditions/logic_callable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@

namespace Monitoring {
namespace intern {
template<typename CallableT, typename... Args>
inline constexpr bool is_const_invocable_v = std::is_invocable_v<const CallableT, Args...>;
template<typename F, typename... Args>
struct is_invocable
: std::is_constructible<std::function<void(Args...)>,
std::reference_wrapper<typename std::remove_reference<F>::type>>
{
};

template<typename CallableT, typename... Args> using is_const_invocable = is_invocable<const CallableT, Args...>;

template<typename CallableT> struct NotCallable
{
explicit NotCallable(CallableT callable) : mCallable(std::move(callable)) {}

template<typename... Args, std::enable_if_t<!intern::is_const_invocable_v<CallableT, Args...>, int> = 0>
template<typename... Args, std::enable_if_t<!intern::is_const_invocable<CallableT, Args...>::value, int> = 0>
auto operator()(Args &&...args)
{
return !mCallable(std::forward<Args>(args)...);
}

template<typename... Args, std::enable_if_t<intern::is_const_invocable_v<CallableT, Args...>, int> = 0>
template<typename... Args, std::enable_if_t<intern::is_const_invocable<CallableT, Args...>::value, int> = 0>
auto operator()(Args &&...args) const
{
return !mCallable(std::forward<Args>(args)...);
Expand All @@ -31,10 +37,13 @@ namespace intern {

template<typename Lhs, typename Rhs, typename Op> struct MergedCallables
{
explicit MergedCallables(Lhs lhs, Rhs rhs, Op op) : mLhs(std::move(lhs)), mRhs(std::move(rhs)), mOp(op) {}
explicit MergedCallables(Lhs &&lhs, Rhs &&rhs, Op &&op)
: mLhs(std::forward<Lhs>(lhs)), mRhs(std::forward<Rhs>(rhs)), mOp(std::forward<Op>(op))
{}

template<typename... Args,
std::enable_if_t<!intern::is_const_invocable_v<Lhs, Args...> || !intern::is_const_invocable_v<Rhs, Args...>,
std::enable_if_t<!intern::is_const_invocable<Lhs, Args...>::value
|| !intern::is_const_invocable<Rhs, Args...>::value,
int> = 0>
auto operator()(Args &&...args)
{
Expand All @@ -44,8 +53,9 @@ namespace intern {
}

template<typename... Args,
std::enable_if_t<intern::is_const_invocable_v<Lhs, Args...> && intern::is_const_invocable_v<Rhs, Args...>, int> =
0>
std::enable_if_t<intern::is_const_invocable<Lhs, Args...>::value
&& intern::is_const_invocable<Rhs, Args...>::value,
int> = 0>
auto operator()(Args &&...args) const
{
const auto res1 = mLhs(std::forward<decltype(args)>(args)...);
Expand All @@ -58,47 +68,54 @@ namespace intern {
Rhs mRhs;
Op mOp;
};

template<typename Lhs, typename Rhs, typename Op> auto MergeCallables(Lhs &&lhs, Rhs &&rhs, Op &&op)
{
return MergedCallables<Lhs, Rhs, Op>(std::forward<Lhs>(lhs), std::forward<Rhs>(rhs), std::forward<Op>(op));
}
}// namespace intern
// Wrapping your callables in this class makes it possible to do logical operations on them.
// The callables must return a bool and take the same parameters.
// In fact, only the first callable needs to be wrapped in this class, the others can be normal callables.
// TODO: static_assert if CallableT is not an actual callable.
// TODO: Forward noexcept.
template<typename CallableT> struct LogicCallable
template<typename CallableT> struct LogicCallableT
{
LogicCallable(CallableT callable) : mCallable(std::move(callable)) {}
LogicCallableT(CallableT callable) : mCallable(std::move(callable)) {}

template<typename... Args, std::enable_if_t<intern::is_const_invocable_v<CallableT, Args...>, int> = 0>
template<typename... Args, std::enable_if_t<intern::is_const_invocable<CallableT, Args...>::value, int> = 0>
auto operator()(Args &&...args) const
{
return mCallable(std::forward<Args>(args)...);
}

template<typename... Args, std::enable_if_t<!intern::is_const_invocable_v<CallableT, Args...>, int> = 0>
template<typename... Args, std::enable_if_t<!intern::is_const_invocable<CallableT, Args...>::value, int> = 0>
auto operator()(Args &&...args)
{
return mCallable(std::forward<Args>(args)...);
}

template<typename OtherCallableT> auto operator||(OtherCallableT otherCallable)
{
auto lamb = intern::MergedCallables(mCallable, std::move(otherCallable), std::logical_or());
return LogicCallable<decltype(lamb)>(lamb);
auto lamb = intern::MergeCallables(mCallable, std::move(otherCallable), std::logical_or<bool>());
return LogicCallableT<decltype(lamb)>(lamb);
}

template<typename OtherCallableT> auto operator&&(OtherCallableT otherCallable)
{
auto lamb = intern::MergedCallables(mCallable, std::move(otherCallable), std::logical_and());
return LogicCallable<decltype(lamb)>(lamb);
auto lamb = intern::MergeCallables(mCallable, std::move(otherCallable), std::logical_and<bool>());
return LogicCallableT<decltype(lamb)>(lamb);
}

auto operator!()
{
auto lamb = intern::NotCallable(mCallable);
return LogicCallable<decltype(lamb)>(lamb);
auto lamb = intern::NotCallable<CallableT>(mCallable);
return LogicCallableT<decltype(lamb)>(lamb);
}

private:
CallableT mCallable;
};

template<typename CallableT> auto LogicCallable(CallableT &&callable) { return LogicCallableT<CallableT>(callable); }
}// namespace Monitoring
Loading

0 comments on commit c00a96c

Please sign in to comment.