Adds further ext deps as-is binaries copies from customers env.
Qt6 Migration CI / migrate (push) Canceled after 0s

This commit is contained in:
torsten committed 2026-10-23 16:13:31 +00:00
1 parent 48129fdab2
commit 48d9b9bd49
3700 files changed
+2132394

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
#pragma once
#include "ddkit/base/ConfigRw.hpp"
#include "ddkit/base/ConfigLoader.hpp"
#include "ddkit/access/System.hpp"
#include <string>
#include <set>
#include <memory>
#include <utility>
namespace ddkit {
namespace access {
/// @brief ConfigLoaderDds holds the ConfigLoader (Config) and the DdsSystem (process-wide dds-initialization)
/// if created before everything else (on the stack), this will do for clean termination.
class ConfigLoaderDds;
typedef std::shared_ptr<ConfigLoaderDds> ConfigLoaderDdsPtr;
class ConfigLoaderDds {
public:
ConfigLoaderDds();
ConfigLoaderDds(const std::string& configFile);
~ConfigLoaderDds();
base::IConfig& config() { return m_configRw; }
base::IConfigWrite& configWrite() { return m_configRw; }
// checks all keys, which start '<section>.' to be '<section>.<key>' with a <key> from given list
// - checks whole config(-file) right now.
// - enables checking from now on in all calls to above config-functions has(), get(), set().
// the checking-function will throw, if a violation is detected.
void registerKnownConfigKey(const std::string& section, const std::string& key);
void reloadConfig(const std::string& configFile);
static ConfigLoaderDdsPtr instance();
private:
// no copying
ConfigLoaderDds(ConfigLoaderDds const&) = delete;
ConfigLoaderDds(ConfigLoaderDds&&) = delete;
void operator=(ConfigLoaderDds const&) = delete;
void operator=(ConfigLoaderDds&&) = delete;
void loadDefaultTerminateHandlers();
std::unique_ptr<base::ConfigLoader> m_configLoader;
base::ConfigRw m_configRw;
};
} // namespace access
} // namespace ddkit
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include "ddkit/access/IConnectUpdate.hpp"
#include "ddkit/access/IConnectCheck.hpp"
#include <mutex>
#include <condition_variable>
namespace ddkit {
namespace access {
class ConnectState final : public IConnectUpdate,
public IConnectCheck {
public:
ConnectState(const std::string& name, const std::string& nameModule, const std::string& nameTopic);
// IConnectUpdate
void setIsConnected() override;
void setIsNotConnected() override;
// IConnectCheck
std::string name() override;
std::string nameModule() override;
std::string nameTopic() override;
bool isConnected() override;
void waitUntilConnected();
private:
std::string m_name;
std::string m_nameModule;
std::string m_nameTopic;
std::recursive_mutex m_mutex;
std::condition_variable_any m_condition;
bool m_isConnected;
// no copying
ConnectState(ConnectState const&) = delete;
ConnectState(ConnectState&&) = delete;
void operator=(ConnectState const&) = delete;
};
typedef std::shared_ptr<ConnectState> ConnectStatePtr;
} // namespace access
} // namespace ddkit
+37
View File
@@ -0,0 +1,37 @@
#pragma once
//
// only ever include DdsWrap.hpp instead of dds/dds.hpp!
//
// - visual studio-mechanism for isystem (external includes), that is avoid warnings in third-party-code, is not
// working with (our) cmake so far.
// - so we need to disable all warnings from dds-vendor "by hand". this is done
// - here, while including dds-headers directly
// - in all wrapper-headers around dds-generated files (which include dds indirectly as well obviously)
// - see genVendorWrap for that.
#ifdef _WIN32
#pragma warning(push, 0)
#endif
#include <dds/dds.hpp>
#ifdef _WIN32
#pragma warning(pop)
#endif
// the ostream-operator (operator<<) for InstanceHandle is declared in connext and cyclone nearly the same way
// - connext: ndds/hpp/dds/core/InstanceHandle.hpp
// - cyclone: ddscxx/dds/core/InstanceHandle.hpp
// but connext implements it inline (delegates to rhs.delegate()), while cyclone does not.
// this seems to be the reason, for that the operator is not usable with cyclone at first glance.
// but we simply need to make it known in the namespace for ADL (argument-dependent-lookup) to work.
namespace dds {
namespace core {
using ::operator<<;
}
} // namespace dds
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include "ddkit/base/Thread.hpp"
#include "ddkit/access/ConfigLoaderDds.hpp"
#include "ddkit/access/DdsWrap.hpp"
#include "ddkit/access/System.hpp"
#include "ddkit/access/ICleanup.hpp"
#include "ddkit/utils/Logger.hpp"
#include <atomic>
namespace ddkit {
namespace access {
class Dispatcher : public base::Thread {
public:
explicit Dispatcher(const std::string& threadName);
Dispatcher(const std::string& threadName, std::shared_ptr<ICleanup> cleanup);
~Dispatcher();
void addReadCondition(const dds::sub::cond::ReadCondition& readCondition);
void removeReadCondition(const dds::sub::cond::ReadCondition& readCondition);
void requestCleanup();
// Thread
void run() override;
void onStop() override;
private:
// System has to be referenced because System::instance() call (and therefore instantiation of the singleton)
// has to happen before the waitset is initialized. Otherwise the waitset would access the policy first and
// the manipulation by System later will throw an exception because the policy is already immutable.
std::shared_ptr<access::ConfigLoaderDds> m_configLoaderDds; // contains System
std::shared_ptr<ICleanup> m_cleanup;
std::recursive_mutex m_addRemoveMutex;
dds::core::cond::WaitSet m_waitset;
dds::core::cond::GuardCondition m_guardCondition;
void callCleanupIf();
Dispatcher(Dispatcher const&) = delete;
void operator=(Dispatcher const&) = delete;
};
} // namespace access
} // namespace ddkit
+17
View File
@@ -0,0 +1,17 @@
#pragma once
namespace ddkit {
namespace access {
class ICleanup {
public:
virtual void cleanup() = 0;
virtual ~ICleanup() = default;
virtual bool isShutdownRequested() = 0;
};
} // namespace access
} // namespace ddkit
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <string>
#include <memory>
namespace ddkit {
namespace access {
class IConnectCheck {
public:
virtual std::string name() = 0;
virtual std::string nameModule() = 0;
virtual std::string nameTopic() = 0;
virtual bool isConnected() = 0;
virtual ~IConnectCheck() = default;
};
typedef std::shared_ptr<IConnectCheck> IConnectCheckPtr;
} // namespace access
} // namespace ddkit
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <memory>
namespace ddkit {
namespace access {
class IConnectUpdate {
public:
virtual void setIsConnected() = 0;
virtual void setIsNotConnected() = 0;
virtual ~IConnectUpdate() = default;
};
typedef std::shared_ptr<IConnectUpdate> IConnectUpdatePtr;
} // namespace access
} // namespace ddkit
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "ddkit/access/QosPattern.hpp"
namespace ddkit {
namespace access {
/// contains one or more QosPatterns and returns them on request by typeName.
class IQosStrategy {
public:
virtual QosPattern selectQosPattern(const std::string& typeName) = 0;
virtual ~IQosStrategy() = default;
};
typedef std::shared_ptr<IQosStrategy> IQosStrategyPtr;
} // namespace access
} // namespace ddkit
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <string>
namespace ddkit {
namespace access {
/// @brief template-independent base-class of topics (needed to have a type for generically store a topic-map)
class ITopic {
public:
virtual std::string topicName() = 0;
virtual bool hasReader() = 0;
virtual void unloadReader() = 0;
virtual void closeReader() = 0;
virtual bool hasWriter() = 0;
virtual void closeWriter() = 0;
virtual ~ITopic() = default;
};
} // namespace access
} // namespace ddkit
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <memory>
namespace ddkit {
namespace access {
class ITopicStrategy {
public:
virtual std::string get(const std::string& typeName) = 0;
virtual ~ITopicStrategy() = default;
protected:
ITopicStrategy() = default;
private:
// no copying
ITopicStrategy(ITopicStrategy const&) = delete;
ITopicStrategy(ITopicStrategy&&) = delete;
void operator=(ITopicStrategy const&) = delete;
void operator=(ITopicStrategy&&) = delete;
};
typedef std::shared_ptr<ITopicStrategy> ITopicStrategyPtr;
} // namespace access
} // namespace ddkit
+226
View File
@@ -0,0 +1,226 @@
#pragma once
#include "ddkit/access/DdsWrap.hpp"
#include "ddkit/access/ConnectState.hpp"
#include "ddkit/utils/Logger.hpp"
namespace ddkit {
namespace access {
std::string policyName(unsigned policyId);
template <class T>
class ListenerTopic : public dds::topic::TopicListener<T> {
public:
void on_inconsistent_topic(
dds::topic::Topic<T>&, dds::core::status::InconsistentTopicStatus const& status) override {
ddkit::log::warn() << "Inconsistent Topic: "
<< dds::topic::topic_type_name<T>::value()
<< ", count=" << status.total_count()
<< "(" << std::showpos << status.total_count_change() << ")";
}
};
template <class T>
class ListenerRead : public dds::sub::DataReaderListener<T> {
ConnectStatePtr m_connectUpdate;
public:
ListenerRead(ConnectStatePtr connectState): m_connectUpdate(connectState) {
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(connectState->nameModule())
<< DDKIT_LOG_VAR_VALUE(connectState->nameTopic());
}
/// @brief We use waitsets and read conditions to get the data more granulary.
/// So we actually dont need this on data here in the dds-listeners.
void on_data_available(dds::sub::DataReader<T>& /* dataReader */) override {
/*DDKIT_LOG_TRACE << std::addressof(dataReader)
<< " topic name: "
<< dataReader.topic_description().name()
<< ", topic type: "
<< dataReader.topic_description().type_name();*/
}
void on_liveliness_changed(
dds::sub::DataReader<T>&, const dds::core::status::LivelinessChangedStatus& status) override {
ddkit::log::debug() << "liveliness changed: "
<< dds::topic::topic_type_name<T>::value() << ", " << status.alive_count() << "/"
<< status.not_alive_count();
}
void on_requested_deadline_missed(
dds::sub::DataReader<T>&, const dds::core::status::RequestedDeadlineMissedStatus&) override {
ddkit::log::warn() << "on_requested_deadline_missed";
}
void on_requested_incompatible_qos(
dds::sub::DataReader<T>& /*reader*/,
const dds::core::status::RequestedIncompatibleQosStatus& status) override {
// When partitions do not match it does not mean that there is a problem.
// It may is intended to direct the dataflow on a logical level.
#if defined(DDS_VENDOR_CONNEXT) || defined(DDS_VENDOR_CYCLONE)
if (status.last_policy_id() != DDS_PARTITION_QOS_POLICY_ID) {
#else
if (true) {
#endif
ddkit::log::warn() << "Reader: Incompatible QoS requested: ("
<< std::to_string(status.last_policy_id()) << "): " << policyName(status.last_policy_id()) << ", "
<< dds::topic::topic_type_name<T>::value() << ", count=" << status.total_count() << "("
<< std::showpos << status.total_count_change() << ")";
}
}
void on_sample_lost(dds::sub::DataReader<T>&, const dds::core::status::SampleLostStatus&) override {
ddkit::log::warn() << "on_sample_lost";
}
void on_sample_rejected(dds::sub::DataReader<T>&, const dds::core::status::SampleRejectedStatus& status) override {
if (status.last_reason() != dds::core::status::SampleRejectedState::not_rejected()) {
ddkit::log::warn() << "on_sample_rejected " << status.last_reason();
}
}
void on_subscription_matched(
dds::sub::DataReader<T>&, const dds::core::status::SubscriptionMatchedStatus& status) override {
ddkit::log::debug() << "Subscription matched: "
<< dds::topic::topic_type_name<T>::value() << ", " << status.current_count();
if (status.current_count()) {
m_connectUpdate->setIsConnected();
} else {
m_connectUpdate->setIsNotConnected();
}
}
virtual ~ListenerRead() {
DDKIT_LOG_TRACE
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameModule())
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameTopic());
}
};
template <class T>
class ListenerWrite : public dds::pub::DataWriterListener<T> {
ConnectStatePtr m_connectUpdate;
public:
ListenerWrite(ConnectStatePtr connectState): m_connectUpdate(connectState) {
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameModule())
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameTopic());
}
void on_liveliness_lost(dds::pub::DataWriter<T>&, dds::core::status::LivelinessLostStatus const&) override {
ddkit::log::warn() << "liveliness lost";
}
void on_offered_deadline_missed(
dds::pub::DataWriter<T>&, dds::core::status::OfferedDeadlineMissedStatus const&) override {
ddkit::log::warn() << "on_offered_deadline_missed";
}
void on_offered_incompatible_qos(
dds::pub::DataWriter<T>&, dds::core::status::OfferedIncompatibleQosStatus const& status) override {
#if defined(DDS_VENDOR_CONNEXT) || defined(DDS_VENDOR_CYCLONE)
if (status.last_policy_id() != DDS_PARTITION_QOS_POLICY_ID) {
#else
if (true) {
#endif
ddkit::log::warn() << "Writer: Incompatible QoS offered: ("
<< std::to_string(status.last_policy_id()) << "): " << policyName(status.last_policy_id()) << ", "
<< dds::topic::topic_type_name<T>::value() << ", count=" << status.total_count() << "("
<< std::showpos << status.total_count_change() << ")";
}
}
void on_publication_matched(
dds::pub::DataWriter<T>&, dds::core::status::PublicationMatchedStatus const& status) override {
ddkit::log::debug() << "Publication matched: " << DDKIT_LOG_VAR_VALUE(status.current_count());
if (status.current_count()) {
m_connectUpdate->setIsConnected();
} else {
m_connectUpdate->setIsNotConnected();
}
}
#if defined(DDS_VENDOR_CONNEXT)
void on_application_acknowledgment(
dds::pub::DataWriter<T>& /*dataWriter*/,
rti::pub::AcknowledgmentInfo const& /*acknowledgment_info*/) override {
DDKIT_LOG_TRACE;
}
void* on_data_request(dds::pub::DataWriter<T>&, rti::core::Cookie const&) override {
DDKIT_LOG_TRACE;
return nullptr;
}
void on_data_return(dds::pub::DataWriter<T>&, void*, rti::core::Cookie const&) override {
DDKIT_LOG_TRACE;
}
void on_destination_unreachable(
dds::pub::DataWriter<T>&, dds::core::InstanceHandle const&, rti::core::Locator const&) override {
DDKIT_LOG_TRACE;
}
void on_instance_replaced(dds::pub::DataWriter<T>&, dds::core::InstanceHandle const& /*handle*/) override {
DDKIT_LOG_TRACE;
}
void on_reliable_reader_activity_changed(
dds::pub::DataWriter<T>&, const rti::core::status::ReliableReaderActivityChangedStatus&) override {
DDKIT_LOG_TRACE;
}
void on_reliable_writer_cache_changed(
dds::pub::DataWriter<T>&, rti::core::status::ReliableWriterCacheChangedStatus const& status) override {
DDKIT_LOG_TRACE;
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.empty_reliable_writer_cache());
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.full_reliable_writer_cache());
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.low_watermark_reliable_writer_cache());
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.high_watermark_reliable_writer_cache());
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.unacknowledged_sample_count());
ddkit::log::debug() << DDKIT_LOG_VAR_VALUE(status.unacknowledged_sample_count_peak());
}
void on_sample_removed(dds::pub::DataWriter<T>&, rti::core::Cookie const&) override {
DDKIT_LOG_TRACE;
}
void on_service_request_accepted(
dds::pub::DataWriter<T>&, rti::core::status::ServiceRequestAcceptedStatus const&) override {
DDKIT_LOG_TRACE;
}
#elif defined(DDS_VENDOR_CYCLONE)
// other vendors may have other extensions
#elif defined(DDS_VENDOR_OPENSPLICE)
// other vendors may have other extensions
#else
#error "DDS_VENDOR not set"
#endif
virtual ~ListenerWrite() {
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameModule())
<< DDKIT_LOG_VAR_VALUE(m_connectUpdate->nameTopic());
}
};
} // namespace access
} // namespace ddkit
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#include "ddkit/base/Config.hpp"
#include "ddkit/access/TopicPoolRead.hpp"
#include "ddkit/access/TopicPoolWrite.hpp"
namespace ddkit {
namespace access {
class ModelMonitor final {
public:
ModelMonitor(
base::Config& config,
bool isWrite,
bool isRmodel,
const std::string& header,
int domain,
const IQosStrategyPtr& qosStrategy,
const ITopicStrategyPtr& topicStrategy);
// start current module for addition
void startModule(const std::string& moduleName);
// ... for current module
template <typename T>
void addTopic();
// listen forever
void doRun();
private:
base::Config& m_config;
bool m_isWrite;
bool m_isRmodel;
std::string m_header;
int m_domain;
std::shared_ptr<Dispatcher> m_dispatcher;
Participant m_participant;
TopicPoolWrite m_topicPoolWrite;
TopicPoolRead m_topicPoolRead;
std::string m_moduleCurrent;
int m_ctCurrent;
int m_ctTotal;
std::map<std::string, int> m_module2ct;
};
template <typename T>
void ModelMonitor::addTopic() {
DDKIT_LOG_TRACE;
std::string typeName = dds::topic::topic_type_name<T>::value();
if (m_isRmodel) {
ddkit::utils::string::removePrefix(typeName, "VendorData::");
}
std::string partFirst = typeName.substr(0, typeName.find("::"));
std::string partLast = typeName.substr(typeName.rfind("::") + 2);
std::string moduleName = partFirst;
std::string topicName = partLast;
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(moduleName);
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(m_moduleCurrent);
if(moduleName != m_moduleCurrent){
ddkit::log::error() << "ModelMonitor::addTopic: mismatch in module name: \"" << m_moduleCurrent << "\" in class and \"" << moduleName << "\" in topic_type_name.";
return;
}
// bei isRmodel muss das config-format anders werden IService.ConfigAbc ...
std::string key = "module." + moduleName + "." + topicName;
bool isOn = m_config.hasKey(key) && m_config.getBoolValue(key);
ddkit::log::trace() << key;
if (isOn) {
++m_ctCurrent;
if (m_isWrite) {
std::ostringstream deadEnd; deadEnd << "not implemented yet"; // todo
ddkit::log::fatal() << deadEnd.str();
throw std::logic_error(deadEnd.str());
// m_topicPoolWrite.createTopicWrite<T>();
} else {
m_topicPoolRead.createTopicRead<T>(
[=](T const& val) { std::cout << m_header << typeName << ": " << val << std::endl; });
}
}
}
} // namespace access
} // namespace ddkit
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "ddkit/access/DdsWrap.hpp"
namespace ddkit {
namespace access {
class Participant {
public:
explicit Participant(int domainId, bool connextExtensibleCompliant=false);
int domain();
dds::domain::DomainParticipant& domainParticipant();
private:
void setConnextXTypesSpecCompliant(bool compliant);
dds::domain::qos::DomainParticipantQos getParticipantQos();
bool m_connextExtensibleCompliant;
int m_domainId;
dds::domain::DomainParticipant m_domainParticipant;
// default copying
};
} // namespace access
} // namespace ddkit
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include "ddkit/access/DdsWrap.hpp"
namespace ddkit {
namespace access {
/// @brief wraps dds::pub::qos::DataWriterQos and dds::sub::qos::DataReaderQos
/// allows defining an arbitrary list of qos-settings.
class QosPattern {
public:
QosPattern();
QosPattern get();
dds::sub::qos::DataReaderQos& qosRead();
dds::pub::qos::DataWriterQos& qosWrite();
dds::topic::qos::TopicQos& qosTopic();
dds::sub::qos::SubscriberQos& qosSub();
dds::pub::qos::PublisherQos& qosPub();
QosPattern& qosReadWrite();
template <typename T>
QosPattern& operator<<(T const& rhs) {
qosRead() << rhs;
qosWrite() << rhs;
qosTopic() << rhs;
return *this;
}
private:
dds::sub::qos::DataReaderQos m_dataReaderQos;
dds::pub::qos::DataWriterQos m_dataWriterQos;
dds::topic::qos::TopicQos m_topicQos;
dds::sub::qos::SubscriberQos m_subscriberQos;
dds::pub::qos::PublisherQos m_publisherQos;
};
class QosPatternDefault : public QosPattern {
public:
QosPatternDefault() {
using namespace dds::core::policy;
qosReadWrite() << Ownership(OwnershipKind::SHARED)
<< Reliability(ReliabilityKind::RELIABLE)
<< Durability(DurabilityKind::TRANSIENT_LOCAL);
}
};
} // namespace access
} // namespace ddkit
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include "ddkit/access/QosPattern.hpp"
namespace ddkit {
namespace access {
/// @brief Tmsif (rmodel-generated-models/appls)
class QosPatternRm : public QosPattern {
public:
QosPatternRm(const std::vector<std::string>& partitions, const bool ignoreLocal);
};
/// @brief Config/Report
class QosPatternRmLateJoin : public QosPatternRm {
public:
QosPatternRmLateJoin(const std::vector<std::string>& partitions, const bool ignoreLocal);
};
/// @brief Notify/Event / Cmd/Request/Response
class QosPatternRmFireForget : public QosPatternRm {
public:
QosPatternRmFireForget(const std::vector<std::string>& partitions, const bool ignoreLocal);
};
} // namespace access
} // namespace ddkit
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "ddkit/access/IQosStrategy.hpp"
#include "ddkit/access/QosPattern.hpp"
namespace ddkit {
namespace access {
// default and example
class QosStrategyDefault : public IQosStrategy {
public:
QosPattern selectQosPattern(const std::string& /*typeName*/) override {
// typeName ignored in this case, set default for all typenames
return QosPatternDefault().get();
}
};
} // namespace access
} // namespace ddkit
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "ddkit/access/IQosStrategy.hpp"
#include "ddkit/access/QosPattern.hpp"
namespace ddkit {
namespace access {
class QosStrategyRm : public IQosStrategy {
public:
QosStrategyRm(const std::vector<std::string>& partitions, const bool ignoreLocal);
QosPattern selectQosPattern(const std::string& typeName) override;
private:
std::vector<std::string> m_partitions;
bool m_ignoreLocal = false;
};
} // namespace access
} // namespace ddkit
+171
View File
@@ -0,0 +1,171 @@
#pragma once
#include "ddkit/access/DdsWrap.hpp"
#include "ddkit/access/Dispatcher.hpp"
#include "ddkit/access/Topic.hpp"
#include "ddkit/access/Listener.hpp"
#include "ddkit/access/ConnectState.hpp"
namespace ddkit {
namespace access {
#if defined(DDS_VENDOR_CONNEXT)
#define DDKIT_USE_KEY_VALUE ON
#ifdef _WIN32
#define DDKIT_COND_TYPE_UNUSED
#else
#define DDKIT_COND_TYPE_UNUSED dds::core::cond::Condition
#endif
#elif defined(DDS_VENDOR_CYCLONE)
#define DDKIT_COND_TYPE_UNUSED dds::core::cond::Condition
#elif defined(DDS_VENDOR_OPENSPLICE)
#define DDKIT_COND_TYPE_UNUSED dds::core::cond::Condition
#else
#error "DDS_VENDOR not set"
#endif
template <typename T>
class Reader final {
public:
Reader(
std::shared_ptr<access::Dispatcher> dispatcher,
std::shared_ptr<Topic<T>> topic,
dds::sub::qos::DataReaderQos dataReaderQos,
dds::sub::qos::SubscriberQos subQos,
std::function<void(T const&)> funcWrite,
std::function<void(T const&)> funcDispose)
: m_dispatcher(dispatcher)
, m_connectState(std::make_shared<ConnectState>(topic->topicName(), topic->topicNameModule(), topic->topicNameTopic()))
, m_listener(std::make_shared<ListenerRead<T> >(m_connectState))
, m_ddsReader(dataReader(topic, m_listener.get(), dataReaderQos, subQos))
, m_dataState(dds::sub::status::DataState::any())
, m_shutdownRequest(false)
, m_funcWrite(funcWrite)
, m_funcDispose(funcDispose)
, m_func([this](DDKIT_COND_TYPE_UNUSED) {
DDKIT_LOG_TRACE;
const dds::sub::LoanedSamples<T> samples = m_ddsReader.select().state(m_dataState).take();
for (const auto& sample : samples) {
if (m_shutdownRequest) return; // fast exit
const auto& sampleInfo = sample.info();
#ifdef DDKIT_USE_KEY_VALUE
const auto& instanceHandle = sampleInfo.instance_handle();
#endif
const auto& dataState = sampleInfo.state();
const auto& instanceState = dataState.instance_state();
using namespace dds::sub::status;
ddkit::log::trace() << "Sample alive:" << (instanceState == InstanceState::alive());
ddkit::log::trace() << "Sample disposed:" << (instanceState == InstanceState::not_alive_disposed());
ddkit::log::trace() << "Sample no_writers:" << (instanceState == InstanceState::not_alive_no_writers());
// How to get partition of sending writer
// only connext and cyclone > 0.10
// auto pubData = dds::sub::matched_publication_data(m_ddsReader, sampleInfo.publication_handle());
// for (auto& n : pubData.partition()->name()) {
// std::cout << "Partition: " << n << std::endl;
// }
if (sampleInfo.valid() && instanceState == InstanceState::alive()) {
const T& t = sample.data();
// callback
if (m_funcWrite) {
ddkit::log::debug() << "received: " << t << ". Callbacking user ...";
m_funcWrite(t);
ddkit::log::trace() << "... usercallback called.";
}
} else {
if (m_funcDispose) {
#ifdef DDKIT_USE_KEY_VALUE
// - 'key_value()' works perfectly for connext
// (and for cyclone+opensplice while explicitly disposing)
// - no (positive) effect on cross-vendor (see top of file)
// - so it is best to stay with native sample.data() for cyclone+opensplice but
// use simple key_value for connext
T t;
m_ddsReader.key_value(t, instanceHandle);
#else
// - vendors, that are able to fetch the key even on dispose-calls via sample.data()
// (they fill in default-ctor-data in the other attrs, because only the key has
// to be transferred via DDS for dispose - same definition on our API - fine).
const T& t = sample.data();
#endif
ddkit::log::debug() << "received for disposing: " << t << ". Callbacking user ...";
m_funcDispose(t);
ddkit::log::trace() << "... usercallback called.";
}
}
}
})
, m_readCondition(m_ddsReader, m_dataState, m_func) {
DDKIT_LOG_TRACE;
m_dispatcher->addReadCondition(m_readCondition);
}
~Reader() {
DDKIT_LOG_TRACE;
unload();
m_ddsReader.close();
}
void unload() {
if (!m_shutdownRequest) {
m_shutdownRequest = true;
m_dispatcher->removeReadCondition(m_readCondition);
}
}
IConnectCheckPtr getConnectCheck() {
return m_connectState;
}
private:
std::shared_ptr<Dispatcher> m_dispatcher;
ConnectStatePtr m_connectState;
std::shared_ptr<ListenerRead<T>> m_listener;
dds::sub::DataReader<T> m_ddsReader;
dds::sub::status::DataState m_dataState;
std::atomic<bool> m_shutdownRequest;
std::function<void(T const&)> m_funcWrite;
std::function<void(T const&)> m_funcDispose;
std::function<void(DDKIT_COND_TYPE_UNUSED)> m_func;
dds::sub::cond::ReadCondition m_readCondition;
/// Note on reader-listeners: see writer-listeners in Writer.hpp
static dds::sub::DataReader<T> dataReader(
std::shared_ptr<Topic<T>> topic,
ListenerRead<T>* listener,
dds::sub::qos::DataReaderQos dataReaderQos,
dds::sub::qos::SubscriberQos subQos) {
DDKIT_LOG_TRACE;
dds::sub::DataReader<T> ddsReader = dds::sub::DataReader<T>(
dds::sub::Subscriber(topic->domainParticipant(), subQos),
topic->ddsTopic(),
dataReaderQos,
listener,
dds::core::status::StatusMask::all());
return ddsReader;
}
// no copying
Reader(Reader const&) = delete;
Reader(Reader&&) = delete;
void operator=(Reader const&) = delete;
};
#undef DDKIT_USE_KEY_VALUE
#undef DDKIT_COND_TYPE_UNUSED
} // namespace access
} // namespace ddkit
+18
View File
@@ -0,0 +1,18 @@
#pragma once
namespace ddkit {
namespace access {
class System {
public:
static System& instance();
private:
System();
~System();
};
} // namespace access
} // namespace ddkit
+141
View File
@@ -0,0 +1,141 @@
#pragma once
#include "ddkit/access/DdsWrap.hpp"
#include "ddkit/access/ITopic.hpp"
#include "ddkit/access/Participant.hpp"
#include "ddkit/access/Listener.hpp"
#include "ddkit/utils/Logger.hpp"
namespace ddkit {
namespace access {
template <typename T>
class Reader;
template <typename T>
using ReaderPtr = std::shared_ptr<Reader<T>>;
template <typename T>
class Writer;
template <typename T>
using WriterPtr = std::shared_ptr<Writer<T>>;
template <typename T>
class Topic final : public ITopic {
public:
dds::domain::DomainParticipant& domainParticipant() { return m_domainParticipant; }
dds::topic::Topic<T> ddsTopic() { return m_ddsTopic; }
std::string typeName() { return dds::topic::topic_type_name<T>::value(); }
std::string topicNameModule() { return m_topicNameModule; }
std::string topicNameTopic() { return m_topicNameTopic; }
// ITopic
std::string topicName() override { return m_topicName; }
bool hasReader() override {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
return m_reader != nullptr;
}
void unloadReader() override {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
DDKIT_LOG_TRACE << typeName();
if (hasReader()) {
m_reader->unload();
}
}
void closeReader() override {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::debug() << "closeReader (" << typeName() << ")";
if (hasReader()) {
m_reader = nullptr;
}
}
bool hasWriter() override {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
return m_writer != nullptr;
}
void closeWriter() override {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::debug() << "closeWriter (" << typeName() << ")";
if (hasWriter()) {
m_writer = nullptr;
}
}
Topic(
dds::domain::DomainParticipant& domainParticipant,
const std::string& topicName,
const std::string& topicNameModule,
const std::string& topicNameTopic,
dds::topic::qos::TopicQos topicQos) try
: m_domainParticipant(domainParticipant)
, m_topicName(topicName)
, m_topicNameModule(topicNameModule)
, m_topicNameTopic(topicNameTopic)
, m_listener(std::make_shared<ListenerTopic<T> >())
, m_ddsTopic(dds::core::null)
, m_reader(nullptr)
, m_writer(nullptr) {
#if defined(DDS_VENDOR_CONNEXT)
m_ddsTopic = dds::topic::find<dds::topic::Topic<T>>(domainParticipant, topicName);
#endif
if (m_ddsTopic == dds::core::null) {
m_ddsTopic = dds::topic::Topic<T>(
m_domainParticipant,
m_topicName,
topicQos,
m_listener.get(), // has to be set in constructor of topic
dds::core::status::StatusMask::all()
);
}
ddkit::log::info() << "Created topic: " << m_topicName;
} catch (dds::core::Exception& e) {
// happens once in a while on connext (if the same topic is ctored twice in same participant)
ddkit::log::fatal() << "construction Topic " << topicName << " failed: " << e.what();
throw std::runtime_error(e.what());
}
void setReader(ReaderPtr<T> reader) {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
m_reader = reader;
}
std::shared_ptr<Writer<T>> writer() {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
return m_writer;
}
void setWriter(WriterPtr<T> writer) {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
m_writer = writer;
}
private:
bool m_isRead;
dds::domain::DomainParticipant& m_domainParticipant;
std::string m_topicName;
std::string m_topicNameModule;
std::string m_topicNameTopic;
std::shared_ptr<ListenerTopic<T>> m_listener;
dds::topic::Topic<T> m_ddsTopic;
std::recursive_mutex m_mutex;
std::shared_ptr<Reader<T>> m_reader;
std::shared_ptr<Writer<T>> m_writer;
// no copying
Topic(Topic const&) = delete;
Topic(Topic&&) = delete;
void operator=(Topic const&) = delete;
};
} // namespace access
} // namespace ddkit
+100
View File
@@ -0,0 +1,100 @@
#pragma once
#include "ddkit/access/ITopic.hpp"
#include "ddkit/access/IQosStrategy.hpp"
#include "ddkit/access/TopicStrategy.hpp"
#include "ddkit/access/Topic.hpp"
// Topic is included and only forward declares Reader,Writer - for writing-only-users we additionaly need the read-side
// for template-instantiiation ... so include everything just in case ...
#include "ddkit/access/Reader.hpp"
#include "ddkit/access/Writer.hpp"
#include "ddkit/utils/string.hpp"
namespace ddkit {
namespace access {
// TopicPool very well could be the (abstract) base-class for TopicPoolRead and TopicPoolWrite again
class TopicPool final {
public:
TopicPool(
dds::domain::DomainParticipant& domainParticipant,
const IQosStrategyPtr& qosStrategy,
const ITopicStrategyPtr& topicStrategy);
template <typename T>
std::string getTopicName() {
DDKIT_LOG_TRACE;
std::string className = dds::topic::topic_type_name<T>::value();
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(className);
std::string topicName = m_topicStrategy->get(className);
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(topicName);
TopicStrategyMapChars topicStrategyMapChars;
std::string topicNameSafe = topicStrategyMapChars.get(topicName);
ddkit::log::trace() << DDKIT_LOG_VAR_VALUE(topicNameSafe);
return topicNameSafe;
}
/// @brief create or get
template <typename T>
std::shared_ptr<Topic<T>> topic() {
DDKIT_LOG_TRACE;
std::string topicName = getTopicName<T>();
if (!hasTopic(topicName)) {
std::string className = dds::topic::topic_type_name<T>::value();
ddkit::utils::string::removePrefixIf(className, "VendorData::");
std::string::size_type pos = className.rfind("::");
std::string partFirst = (pos == std::string::npos) ? "no-module" : className.substr(0, pos);
std::string partLast = (pos == std::string::npos) ? className : className.substr(pos + 2);
std::string topicNameModule = partFirst;
std::string topicNameTopic = partLast;
m_name2topic.insert(std::make_pair(topicName, std::make_shared<Topic<T>>(
m_domainParticipant,
topicName,
topicNameModule,
topicNameTopic,
m_qosStrategy->selectQosPattern(className).qosTopic()
)));
}
return std::dynamic_pointer_cast<Topic<T>>(getTopic(topicName));
}
QosPattern qosPattern(const std::string& typeName) { return m_qosStrategy->selectQosPattern(typeName); }
template <typename T> // probably not needed with template-param
QosPattern qosPattern() {
std::string typeName = dds::topic::topic_type_name<T>::value();
return qosPattern(typeName);
}
bool hasTopic(const std::string& topicName);
std::shared_ptr<ITopic> getTopic(const std::string& topicName);
bool hasReaders();
void closeReaders();
void closeWriters();
void unloadReaders();
private:
dds::domain::DomainParticipant& m_domainParticipant;
IQosStrategyPtr m_qosStrategy;
ITopicStrategyPtr m_topicStrategy;
std::recursive_mutex m_mutex;
std::map<std::string, std::shared_ptr<ITopic>> m_name2topic;
// no copying
TopicPool(TopicPool const&) = delete;
TopicPool(TopicPool&&) = delete;
void operator=(TopicPool const&) = delete;
};
typedef std::shared_ptr<TopicPool> TopicPoolPtr;
} // namespace access
} // namespace ddkit
+78
View File
@@ -0,0 +1,78 @@
#pragma once
#include "ddkit/access/TopicPool.hpp"
#include "ddkit/access/Topic.hpp"
#include "ddkit/access/Dispatcher.hpp"
#include "ddkit/access/Reader.hpp"
#include "ddkit/utils/string.hpp"
#include <utility>
namespace ddkit {
namespace access {
class TopicPoolRead final {
public:
TopicPoolRead(
Participant& participant,
const IQosStrategyPtr& qosStrategy,
const ITopicStrategyPtr& topicStrategy,
std::shared_ptr<Dispatcher> dispatcher);
~TopicPoolRead();
// create Topic and Reader and register function for beeing callbacked by given dispatcher
// (a second callback may be given for reading disposes as well)
// todo name is historical, could be createReader
template <typename T>
void createTopicRead(std::function<void(T const&)> func, std::function<void(T const&)> funcDispose = nullptr) {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
std::string topicName = m_topicPool.getTopicName<T>();
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
if(!topic) {
ddkit::log::error() << "TopicPoolRead::createTopicRead: no topic in topic pool.";
return;
}
if(topic->hasReader()) {
ddkit::log::error() << "TopicPoolRead::createTopicRead: Reader (" << topicName << ") already exists.";
return;
}
QosPattern qosPattern = m_topicPool.qosPattern(topic->typeName());
dds::sub::qos::DataReaderQos dataReaderQos = qosPattern.qosRead();
dds::sub::qos::SubscriberQos subQos = qosPattern.qosSub();
auto reader = std::make_shared<Reader<T>>(m_dispatcher, topic, dataReaderQos, subQos, func, funcDispose);
topic->setReader(reader);
}
// to be able to call with member-function-callbacks as well - transform to std::function
// - this is used in ldm/test-context so far, no dispose-callback used here so far ...
template <typename T, typename U>
void createTopicRead(void (U::*funcPtr)(T const&), U& u) {
DDKIT_LOG_TRACE;
createTopicRead<T>(std::bind(funcPtr, &u, std::placeholders::_1));
}
bool hasReaders();
void closeReaders();
void unloadReaders();
private:
std::recursive_mutex m_mutex;
TopicPool m_topicPool;
std::shared_ptr<Dispatcher> m_dispatcher;
// no copying
TopicPoolRead(TopicPoolRead const&) = delete;
TopicPoolRead(TopicPoolRead&&) = delete;
void operator=(TopicPoolRead const&) = delete;
};
} // namespace access
} // namespace ddkit
+137
View File
@@ -0,0 +1,137 @@
#pragma once
#include "ddkit/access/TopicPool.hpp"
#include "ddkit/access/Topic.hpp"
#include "ddkit/access/Writer.hpp"
#include "ddkit/utils/system.hpp"
namespace ddkit {
namespace access {
class TopicPoolWrite final {
public:
TopicPoolWrite(
Participant& participant, const IQosStrategyPtr& qosStrategy, const ITopicStrategyPtr& topicStrategy);
~TopicPoolWrite();
// create or get writer
template <typename T>
std::shared_ptr<Writer<T>> writer() {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
createTopicWriteIf<T>(); // must be done here and not in Topic (because TopicPool and qos access needed)
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
if(topic) {
auto writer = topic->writer();
if(!writer){
ddkit::log::error() << "TopicPoolWrite::writer: no writer in topic";
}
return writer;
} else {
ddkit::log::error() << "TopicPoolWrite::writer: no topic in topic pool";
}
return nullptr;
}
// shortcut, no interface+virtual possible (templates)
template <class T>
void write(T const& t) {
bool isOkUnconnected = false;
bool isThrowUnconnected = false;
writeIntern(t, isOkUnconnected, isThrowUnconnected);
}
template <class T>
void writeUnconnectedOk(T const& t) {
bool isOkUnconnected = true;
bool isThrowUnconnected = false;
writeIntern(t, isOkUnconnected, isThrowUnconnected);
}
template <class T>
void writeUnconnectedThrow(T const& t) {
bool isOkUnconnected = false;
bool isThrowUnconnected = false;
writeIntern(t, isOkUnconnected, isThrowUnconnected);
}
private:
template <typename T>
void writeIntern(T const& t, bool isOkUnconnected, bool isThrowUnconnected) {
ddkit::log::trace() << "writing " << dds::topic::topic_type_name<T>::value() << ":" << t;
createTopicWriteIf<T>();
std::unique_lock<std::recursive_mutex> lock(m_mutex);
auto currentWriter = writer<T>();
if(currentWriter){
currentWriter->send(t, isOkUnconnected, isThrowUnconnected);
} else {
ddkit::log::error() << "TopicPoolWrite::writeIntern: no writer in topic pool";
}
}
template <typename T>
void createTopicWrite() {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
std::string topicName = m_topicPool.getTopicName<T>();
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
std::string typeName = topic->typeName();
if(!topic) {
ddkit::log::error() << "TopicPoolWrite::createTopicWrite: no topic in topic pool.";
return;
}
if(topic->hasWriter()) {
ddkit::log::error() << "TopicPoolWrite::createTopicWrite: Writer (" << topicName << ") already exists.";
return;
}
QosPattern qosPattern = m_topicPool.qosPattern(typeName);
dds::pub::qos::DataWriterQos dataWriterQos = qosPattern.qosWrite();
dds::pub::qos::PublisherQos pubQos = qosPattern.qosPub();
auto writer = std::make_shared<Writer<T>>(topic, dataWriterQos, pubQos);
topic->setWriter(writer);
}
template <class T>
void createTopicWriteIf() {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
std::shared_ptr<Topic<T>> topic = m_topicPool.topic<T>();
if (topic && !topic->hasWriter()) {
createTopicWrite<T>();
}
}
public:
template <class T>
void dispose(T const& t) {
std::unique_lock<std::recursive_mutex> lock(m_mutex);
auto currentWriter = writer<T>();
if(currentWriter){
currentWriter->dispose(t);
} else {
ddkit::log::error() << "TopicPoolWrite::dispose: no writer in topic pool";
}
}
void closeWriters();
private:
std::recursive_mutex m_mutex;
TopicPool m_topicPool;
TopicPoolWrite(TopicPoolWrite const&) = delete;
void operator=(TopicPoolWrite const&) = delete;
};
} // namespace access
} // namespace ddkit
+80
View File
@@ -0,0 +1,80 @@
#pragma once
#include "ddkit/access/ITopicStrategy.hpp"
#include <string>
namespace ddkit {
namespace access {
class TopicStrategyRemoveNamespaces : public ITopicStrategy {
public:
std::string get(const std::string& typeName) override;
};
/// @brief replace "::" with "__" (as for example cyclone does not like '::' in topic-names)
class TopicStrategyReplaceColons : public ITopicStrategy {
public:
std::string get(const std::string& typeName) override;
};
/// @brief simply prepend the prefix (plus "_") - nothing else
class TopicStrategyPrefix : public ITopicStrategy {
public:
TopicStrategyPrefix(const std::string& prefix);
std::string get(const std::string& typeName) override;
private:
std::string m_prefix;
};
/// @brief maps all 'unallowed' characters (everything besides [a-zA-Z0-9]) to '_' - implicitly called in TopicPool - always!
class TopicStrategyMapChars : public ITopicStrategy {
public:
TopicStrategyMapChars();
std::string get(const std::string& orig) override;
};
/// @brief SensorService + VendorData::M_Sensor::IService::ConfigSth -> ddkit_SensorService_Sensor_c2s_ConfigSth
class TopicStrategyRmodel : public ITopicStrategy {
public:
TopicStrategyRmodel(const std::string& prefix);
std::string get(const std::string& typeName) override;
private:
TopicStrategyReplaceColons m_tnsReplaceColons;
TopicStrategyPrefix m_tnsPrefix;
};
/// @brief module::name -> module_name
class TopicStrategySimple : public ITopicStrategy {
public:
std::string get(const std::string& typeName) override;
};
/// @brief remove big-char-prefixes and -suffixes and replace colons by underscore
/// - P_Navigation_Reference_PSM::C_Angular_Motion --> Navigation_Reference__Angular_Motion
class TopicStrategyStd : public ITopicStrategy {
public:
std::string get(const std::string& typeName) override;
};
} // namespace access
} // namespace ddkit
+117
View File
@@ -0,0 +1,117 @@
#pragma once
#include "ddkit/access/DdsWrap.hpp"
#include "ddkit/access/Topic.hpp"
#include "ddkit/access/Listener.hpp"
#include "ddkit/access/ConnectState.hpp"
#include "ddkit/utils/Logger.hpp"
namespace ddkit {
namespace access {
template <typename T>
class Writer final {
public:
explicit Writer(std::shared_ptr<Topic<T>> topic, dds::pub::qos::DataWriterQos dataWriterQos, dds::pub::qos::PublisherQos pubQos)
: m_connectState(std::make_shared<ConnectState>(topic->topicName(), topic->topicNameModule(), topic->topicNameTopic()))
, m_listener(std::make_shared<ListenerWrite<T> >(m_connectState))
, m_writer(dataWriter(topic, m_listener.get(), dataWriterQos, pubQos)) {
DDKIT_LOG_TRACE;
}
~Writer() {
DDKIT_LOG_TRACE;
// ddkit::log::info() << "closing writer!";
m_writer.close();
}
bool isConnected() { return m_connectState->isConnected(); }
void waitUntilConnected() { m_connectState->waitUntilConnected(); }
IConnectCheckPtr getConnectCheck() { return m_connectState; }
/// @brief isOkUnconnected == true -> do not warn about write while not connected
/// - one could set this on a late-join-topic to avoid the warnings
/// isThrowUnconnected == true -> do throw momentarily
/// - one could set this on a 'checked' write ('Cmd')
void send(T const& sample, bool isOkUnconnected, bool isThrowUnconnected) {
ddkit::log::debug() << "send: " << DDKIT_LOG_VAR_VALUE(sample);
bool isConnected = m_connectState->isConnected();
// return immediately, if Service for command is not yet connected (and told to throw)
if (!isConnected && isThrowUnconnected) {
throw std::runtime_error("Service for Cmd is unavailable yet - try later.");
}
// todo: as monitor-sessions are not distinguished so far, this (direct) exception will not be thrown,
// if a monitor is running and connected
// warn about probably lost samples (if not told otherwise)
if (!isConnected && !isOkUnconnected) {
ddkit::log::info() << "Writer not connected while sending (" << dds::topic::topic_type_name<T>::value() << ").";
}
// do the write
m_writer.write(sample);
}
void dispose(T const& sample) {
DDKIT_LOG_TRACE;
ddkit::log::debug() << "dispose: " << DDKIT_LOG_VAR_VALUE(sample);
// Get handle of instance
auto handle = m_writer.lookup_instance(sample);
// Instance has to be known
if (handle.is_nil()) {
ddkit::log::error() << "Tried to remove object \"" << sample << "\", which does not exist in dds.";
return;
}
// We have to do both `dispose_instance` and `unregister_instance`
// to fully free the instance. If we would just dispose the instance
// the instance would remain stored by the reader and writer since it
// remains `active`. Only after the `unregister_instance` the instance
// has no associated writer and can be freed.
m_writer.dispose_instance(handle);
m_writer.unregister_instance(handle);
}
private:
ConnectStatePtr m_connectState;
std::shared_ptr<ListenerWrite<T>> m_listener;
dds::pub::DataWriter<T> m_writer;
/// Note on writer-listeners:
/// - listeners have to be set in the constructor of the writer, because
/// an event could be missing, when the listener is set afterwards
/// - all depending on how fast discovery etc is, see also here:
/// https://github.com/eclipse-cyclonedds/cyclonedds-cxx/issues/378#issuecomment-1463626212
static dds::pub::DataWriter<T> dataWriter(
std::shared_ptr<Topic<T>> topic,
ListenerWrite<T>* listener,
dds::pub::qos::DataWriterQos dataWriterQos,
dds::pub::qos::PublisherQos pubQos) {
DDKIT_LOG_TRACE;
dds::pub::DataWriter<T> ddsWriter = dds::pub::DataWriter<T>(
dds::pub::Publisher(topic->domainParticipant(), pubQos),
topic->ddsTopic(),
dataWriterQos,
listener,
dds::core::status::StatusMask::all());
return ddsWriter;
}
// no copying
Writer(Writer const&) = delete;
Writer(Writer&&) = delete;
void operator=(Writer const&) = delete;
};
} // namespace access
} // namespace ddkit
+99
View File
@@ -0,0 +1,99 @@
#pragma once
#include <random>
#include <string>
#include <set>
#include <ostream>
namespace ddkit {
namespace actors {
struct ActorInfo;
struct ActorConfiguration;
// serviceName must be simple (a-z...)
void checkApiServiceName(const std::string& serviceName);
void checkServiceNameIntern(const std::string& serviceName);
// M_Mount::IService
std::string interfaceNameApi(bool isService, const std::string& module);
// M_Mount::Service
std::string serviceClientNameApi(bool isService, const std::string& module);
std::ostream& operator<<(std::ostream& s, ActorConfiguration const& rhs);
struct ActorConfiguration {
ActorConfiguration(
const std::string& module,
bool isService,
int domain,
const std::string& serviceName);
ActorConfiguration(const ddkit::actors::ActorInfo& actorInfo);
ActorConfiguration() = default;
operator std::string() const {
if (serviceName.empty()) {
return std::string() + "(" + serviceClientNameApi(isService, module) + ", " + std::to_string(domain) + ", <no-servicename>)";
}
return std::string() + "(" + serviceClientNameApi(isService, module) + ", " + std::to_string(domain) + ", \"" + serviceName + "\")";
}
bool operator==(ActorConfiguration const& rhs) const;
bool operator<(ActorConfiguration const& rhs) const;
std::string module;
bool isService;
int domain;
std::string serviceName;
};
/// @brief this is "ServiceInfo" / "ClientInfo" really. Do not mistake this for ddkit_intern::ActorInfo (idl-generated class)
/// for monitoring applications like Listener
/// - do not use in other cases.
struct ActorInfo {
ActorInfo() = default;
ActorConfiguration config;
// also part of config (needed to disambiguate clients (multiple of same config allowed in network), also useful for error-detection of services)
std::string actorId;
int32_t processId;
std::string hostName;
std::string procName;
bool isReading;
std::vector<std::string> openReaders;
bool isWriting;
std::vector<std::string> openWriters;
// todo: maybe implement more informations here about the inherited interfaces? See section 7,
// possible Inspector-improvements
// maybe something like 'std::map<std::string, std::vector<std::string>> m_module2openReadersModule' would be
// fine here, but probably it's only a matter of display. Inspector can show everything without changes here.
std::string clientName; // client-display-Name, on service: filled with "undefined"
// on client: actorId or setName/create/add-given user-value
// bool isMonitor - no, not needed, the monitoring-actorInfos are not sent to the dds ... so true never shows up
// debug
friend std::ostream& operator<<(std::ostream& s, ActorInfo const& rhs);
operator std::string() const;
// set-order
bool operator<(ActorInfo const& rhs) const;
// default copying
};
typedef ActorInfo ServiceInfo;
typedef ActorInfo ClientInfo;
} // namespace actors
} // namespace ddkit
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include "ddkit/base/ThreadSync.hpp"
#include "ddkit/access/TopicPoolWrite.hpp"
#include "ddkit/access/TopicPoolRead.hpp"
#include "ddkit/idls/ActorInfo.hpp"
#include "ddkit/actors/ActorInfo.hpp"
#include "ddkit/actors/ILocalServices.hpp"
namespace ddkit {
namespace actors {
/// @brief DDS-Database for all ddkit_intern::ActorInfo on the network.
/// The data is added/removed by the ActorInfoDbCaretaker.
class ActorInfoDb {
public:
ActorInfoDb(ILocalServices& localServices);
~ActorInfoDb();
void updateActorInfo(ddkit_intern::ActorInfo actorInfo, int domainId);
void removeActorInfo(ddkit_intern::ActorInfo actorInfo, int domainId);
// for "find()"
std::vector<ActorInfo> findActorInfo(const std::string& module, bool isService, int domain);
std::vector<ActorInfo> findActorInfo(
const std::string& module, bool isService, int domain, const std::string& serviceName);
std::vector<ActorInfo> findActorInfo(ActorConfiguration config);
std::vector<ActorInfo> findActorInfo(const std::string& actorId);
// for "isRunning()"
bool hasService(const std::string& module, int domain, const std::string& serviceName);
// for "wait()"
void waitForService(const std::string& module, int domain, const std::string& serviceName);
// access meta-infos for callbackInfo
std::string clientActorId2clientName(const std::string& clientActorId);
private:
std::recursive_mutex m_mutex;
std::condition_variable_any m_dbChanged;
ILocalServices& m_localServices;
std::vector<ddkit_intern::ActorInfo> m_actorInfos;
std::map<std::string, std::string> m_discardedActorIdToClientName;
// no copying
ActorInfoDb(ActorInfoDb const&) = delete;
ActorInfoDb(ActorInfoDb&&) = delete;
void operator=(ActorInfoDb const&) = delete;
};
} // namespace actors
} // namespace ddkit
@@ -0,0 +1,43 @@
#pragma once
#include "ddkit/base/ThreadSync.hpp"
#include "ddkit/access/TopicPoolWrite.hpp"
#include "ddkit/access/TopicPoolRead.hpp"
#include "ddkit/idls/ActorInfo.hpp"
#include "ddkit/actors/ActorInfo.hpp"
#include "ddkit/actors/ActorInfoDb.hpp"
namespace ddkit {
namespace actors {
ActorConfiguration actorInfoToActorConfiguration(ddkit_intern::ActorInfo actorInfo);
ActorInfo actorInfoToActorInfo(const ddkit_intern::ActorInfo& ddsActorInfo);
/// @brief Caretaker for actorInfo.
/// Registers for ActorInfo-msgs on dds and stores them in ActorInfoDb.
class ActorInfoDbCaretaker {
public:
ActorInfoDbCaretaker(ActorInfoDb& db);
~ActorInfoDbCaretaker();
void init(access::Participant& participant, std::shared_ptr<access::Dispatcher> dispatcher);
void close();
void onWrite_actorInfo(const ddkit_intern::ActorInfo& actorInfo);
void onDispose_actorInfo(const ddkit_intern::ActorInfo& actorInfo);
private:
ActorInfoDb& m_db;
access::IQosStrategyPtr m_qosStrategy;
access::ITopicStrategyPtr m_topicStrategy;
std::unique_ptr<access::TopicPoolRead> m_topicPoolRead;
int m_domainId;
};
} // namespace actors
} // namespace ddkit
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "ddkit/base/ThreadSync.hpp"
#include "ddkit/access/TopicPoolWrite.hpp"
#include "ddkit/access/TopicPoolRead.hpp"
#include "ddkit/idls/ActorInfo.hpp"
#include "ddkit/actors/ActorInfo.hpp"
#include "ddkit/actors/ActorInfoDb.hpp"
namespace ddkit {
namespace actors {
/// @brief Encapsulation of a dds-writer for ActorInfo-messages (per domain) / SessionImpl uses.
class ActorInfoWriter {
public:
explicit ActorInfoWriter(access::Participant& participant);
void write(const ddkit_intern::ActorInfo& actorInfo);
void dispose(const ddkit_intern::ActorInfo& actorInfo);
private:
int m_domain;
access::IQosStrategyPtr m_qosStrategy;
access::ITopicStrategyPtr m_topicStrategy;
access::TopicPoolWrite m_topicPoolWrite;
};
} // namespace actors
} // namespace ddkit
+382
View File
@@ -0,0 +1,382 @@
#pragma once
#include "ddkit/utils/assert.hpp"
#include "ddkit/actors/Key.hpp"
#include "ddkit/actors/SessionManager.hpp"
#include "ddkit/actors/SessionImpl.hpp"
#include "ddkit/actors/SimpleActor.hpp"
namespace ddkit {
namespace actors {
/// @brief The calls (add/create/remove/remove/shutdown/shutdown) from the generated code are delegated here.
/// We try to create/remove Actors as much as "normal" as it would be done via Session/Service/Client
/// but of course there are some differences, as two calls may create only one Actor etc.
/// Keep one SimpleActorPtr as replacement for the not-existing Service/Client-proxys in own list.
class BackwardManager {
public:
static BackwardManager& instance();
/// @brief called from generated code: ObsFactory::add()
template <typename Observer>
void createObserver(
const std::string& serviceName,
int domain,
bool isService,
const std::string& moduleName,
typename Observer::TypeUser* callbacks,
const std::vector<std::string>& methods,
const std::string& clientName = "") {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "add(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< " Please note that it may be removed in future versions.";
ddkit::log::debug() << "create observer by key api: " << serviceName << ", " << std::to_string(domain);
checkApiServiceName(serviceName);
checkObserverType<Observer>();
ActorConfiguration config(moduleName, isService, domain, serviceName);
SimpleActorPtr actor = createOrGetActor(serviceName, domain, isService, moduleName);
DDKIT_THROW_ON_FALSE_INFO(actor, "Failed to create actor");
IObserverPtr observer = actor->createObserver<Observer>(*callbacks, methods);
// if empty there is no need to send data over the wire
if (!clientName.empty() && !isService) {
actor->setClientName(clientName);
}
// global maps
m_observer2actorConfig.insert(std::make_pair(observer, config));
typeUser2observerMap<Observer>().insert(std::make_pair(callbacks, observer));
}
/// @brief called from generated code: Factory::create()
template <typename Sender>
typename Sender::TypeUser* createSender(
const std::string& serviceName,
int domain,
bool isService,
const std::string& moduleName,
const std::vector<std::string>& methods,
const std::string& clientName = "") {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "create(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< "Please note that it may be removed in future versions.";
ddkit::log::debug() << "create sender by key api: " << moduleName;
checkApiServiceName(serviceName);
checkSenderType<Sender>();
ActorConfiguration config(moduleName, isService, domain, serviceName);
SimpleActorPtr actor = createOrGetActor(serviceName, domain, isService, moduleName);
DDKIT_THROW_ON_FALSE_INFO(actor, "Failed to create actor");
ISenderPtr isender = actor->createSender<Sender>(methods);
DDKIT_THROW_ON_FALSE_INFO(isender, "BackwardManager::createSender: could not create sender");
// if empty there is no need to send data over the wire
if (!clientName.empty()) {
actor->setClientName(clientName);
}
// return raw-ptr for old C-API
Sender* sender = dynamic_cast<Sender*>(isender.get()); // downcast - Sender inherits ISender
DDKIT_THROW_ON_FALSE(sender);
typename Sender::TypeUser* senderUser = sender; // upcast - Sender inherits IService/IClient
// global maps
std::unique_lock<std::recursive_mutex> lockMaps(m_mutex);
m_sender2actorConfig.insert(std::make_pair(isender, config));
typeUser2senderMap<Sender>().insert(std::make_pair(senderUser, isender));
return senderUser;
}
/// @brief called from generated code: ObsFactory::remove()
template <typename Observer>
void removeObserverByObserverUser(
typename Observer::TypeUser* observerUser, bool isService, const std::string& moduleName) {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "remove(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< "Please note that it may be removed in future versions.";
ddkit::log::debug() << "Remove Observer By Observer User: " << moduleName;
{
checkObserverType<Observer>();
DDKIT_THROW_ON_FALSE_INFO(observerUser, interfaceNameApi(isService, moduleName) + "ObsFactory::remove()"
+ " called with Observer* == nullptr ?");
// global maps
DDKIT_THROW_ON_FALSE_INFO(typeUser2observerMap<Observer>().find(observerUser) != typeUser2observerMap<Observer>().end(),
interfaceNameApi(isService, moduleName) + "ObsFactory::remove()"
+ " called with Observer* not given to " + interfaceNameApi(isService, moduleName)
+ "ObsFactory::add*() before? (or removed twice?)");
IObserverPtr observer = typeUser2observerMap<Observer>().at(observerUser);
DDKIT_THROW_ON_FALSE_INFO(observer, "removeObserverByObserverUser: observer not found");
ActorConfiguration config = m_observer2actorConfig.at(observer);
ddkit::log::debug() << "called Obs...remove() on " << config;
DDKIT_THROW_ON_FALSE(config.isService == isService);
DDKIT_THROW_ON_FALSE(config.module == moduleName);
// global maps
m_observer2actorConfig.erase(observer);
typeUser2observerMap<Observer>().erase(typeUser2observerMap<Observer>().find(observerUser));
SessionImplPtr sessionImpl = findSession(config.domain);
if (sessionImpl) {
SimpleActorPtr actor = sessionImpl->findActor(config.serviceName, config.isService, config.module);
if (actor) {
if (actor->hasSender()) {
ddkit::log::warn() << "The actor still has a sender, the observer will be deleted after sender is also destoryed!"
<< " Consider using the OO-Api.";
} else {
auto it = m_config2actor.find(config);
if (it != m_config2actor.end()) {
if (m_config2actor.at(config) == actor) {
m_config2actor.erase(it);
actor->shutdown();
// wait until dispatcher etc are done.
while (actor.use_count() > 1) {
ddkit::utils::system::msSleep(10);
}
}
}
}
}
sessionImpl.reset(); // local hold ptr
removeSessionIfEmpty(config.domain);
}
}
checkIfEmpty();
}
/// @brief called from generated code: Factory::remove()
template <typename Sender>
void removeSenderBySenderUser(typename Sender::TypeUser* senderUser, bool isService, const std::string& moduleName) {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "remove(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< "Please note that it may be removed in future versions.";
ddkit::log::debug() << "RemoveSender By Sender User: " << moduleName;
{
checkSenderType<Sender>();
DDKIT_THROW_ON_FALSE_INFO(senderUser, interfaceNameApi(isService, moduleName) + "Factory::remove()"
+ " called with Sender* == nullptr ?");
// global maps
DDKIT_THROW_ON_FALSE_INFO(typeUser2senderMap<Sender>().find(senderUser) != typeUser2senderMap<Sender>().end(),
interfaceNameApi(isService, moduleName) + "Factory::remove()"
+ " called with Sender* not received from " + interfaceNameApi(isService, moduleName)
+ "Factory::create() before? (or removed twice?)");
ISenderPtr sender = typeUser2senderMap<Sender>().at(senderUser);
DDKIT_THROW_ON_FALSE_INFO(sender, "Sender not found");
ActorConfiguration config = m_sender2actorConfig.at(sender);
ddkit::log::debug() << "called ...remove() on " << config;
DDKIT_THROW_ON_FALSE(config.isService == isService);
DDKIT_THROW_ON_FALSE(config.module == moduleName);
// remove sender from global maps
m_sender2actorConfig.erase(sender);
typeUser2senderMap<Sender>().erase(typeUser2senderMap<Sender>().find(senderUser));
SessionImplPtr sessionImpl = findSession(config.domain);
if (sessionImpl) {
SimpleActorPtr actor = sessionImpl->findActor(config.serviceName, config.isService, config.module);
if (actor) {
actor->discardSender();
if (actor->hasObserver()) {
// still has a observer dont shutdown actor!
ddkit::log::warn() << "There is still a observer, make sure to delete it too."
<< " Consider using the new OO-Api.";
} else {
ddkit::log::debug() << "Does not have a observer, we can shutdown the actor.";
auto configIt = m_config2actor.find(config);
if (configIt != m_config2actor.end()) {
if (m_config2actor.at(config) == actor) {
m_config2actor.erase(configIt);
actor->shutdown();
// wait until dispatcher etc are done.
while (actor.use_count() > 1) {
ddkit::utils::system::msSleep(10);
}
}
}
}
}
sessionImpl.reset(); // local hold session-ptr
removeSessionIfEmpty(config.domain);
}
}
checkIfEmpty();
}
/// @brief called from generated code: ObsFactory::shutdown()
template <typename Observer>
void shutdownObservers(bool isService, const std::string& moduleName) {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "shutdown(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< "Please note that it may be removed in future versions.";
ddkit::log::debug() << "shutdown observers: " << moduleName;
checkObserverType<Observer>();
typedef typename Observer::TypeUser TypeUser;
std::vector<TypeUser*> observerUsers;
for (auto& p : typeUser2observerMap<Observer>()) {
observerUsers.push_back(p.first);
}
for (TypeUser* typeUser : observerUsers) {
removeObserverByObserverUser<Observer>(typeUser, isService, moduleName);
}
}
/// @brief called from generated code: Factory::shutdown()
template <typename Sender>
void shutdownSenders(bool isService, const std::string& moduleName) {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "shutdown(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< "Please note that it may be removed in future versions.";
ddkit::log::debug() << "Shutdown senders: " << moduleName;
checkSenderType<Sender>();
typedef typename Sender::TypeUser TypeUser;
std::vector<TypeUser*> senderUsers;
for (auto& p : typeUser2senderMap<Sender>()) {
senderUsers.push_back(p.first);
}
for (TypeUser* typeUser : senderUsers) {
removeSenderBySenderUser<Sender>(typeUser, isService, moduleName);
}
}
/// @brief called from generated code: ObsFactory::getSource()
template <typename Observer>
std::string getSource(bool isService, const std::string& moduleName) {
DDKIT_LOG_TRACE;
std::unique_lock<std::recursive_mutex> lock(m_mutex);
ddkit::log::warn() << "getSource(): You are using the deprecated C-Style API. "
<< "It is recommended to upgrade to the new object-oriented API. "
<< "Please note that it may be removed in future versions. "
<< "Use ddkit::actors::CallbackInfo::current(); instead.";
CallbackInfo callbackInfo = SessionManager::instance().callbackInfo();
bool isToServiceReal = callbackInfo.isFromClient;
if (isService != isToServiceReal) {
ddkit::log::warn() << "getSource() was called on ObsFactory of " << interfaceNameApi(isService, moduleName)
<< " but callback right now is sending data to "
<< serviceClientNameApi(isToServiceReal, moduleName) << ". Probably one should use \""
<< interfaceNameApi(isToServiceReal, moduleName) << "ObsFactory\" instead of \""
<< interfaceNameApi(isService, moduleName) << "ObsFactory\", to remove this warning.";
}
// as "source" we gave back the serviceName or the clientId, depending on the side
if (callbackInfo.isFromClient) {
// client called service
return callbackInfo.clientName; // this is sendingActor (=clientActorId) or user-given clientName
} else {
// service called client
return callbackInfo.serviceName;
}
}
SessionImplPtr createOrGetSession_(int domain);
bool isClean() const;
private:
std::recursive_mutex m_mutex;
std::map<int, SessionImplPtr> m_domain2session;
std::map<ActorConfiguration, SimpleActorPtr> m_config2actor; // holding Actors exactly as long, as add/create/remove tells
// Pointers to actors-configs
std::map<IObserverPtr, ActorConfiguration> m_observer2actorConfig;
std::map<ISenderPtr, ActorConfiguration> m_sender2actorConfig;
BackwardManager();
~BackwardManager();
SimpleActorPtr createOrGetActor(const std::string& serviceName, int domain, bool isService, const std::string& moduleName);
SessionImplPtr findSession(int domain);
SessionImplPtr createOrGetSession(int domain);
void removeSessionIfEmpty(int domain);
void checkIfEmpty();
// these functions are used to circumvent the fact das data members cant be templated
// which is only somewhat fine since BackwardManger is a singleton class
template <typename Sender> std::map<typename Sender::TypeUser*, ISenderPtr>& typeUser2senderMap() {
static std::map<typename Sender::TypeUser*, ISenderPtr> s_typeUser2sender;
return s_typeUser2sender;
}
template <typename Observer> std::map<typename Observer::TypeUser*, IObserverPtr>& typeUser2observerMap() {
static std::map<typename Observer::TypeUser*, IObserverPtr> s_typeUser2observer;
return s_typeUser2observer;
}
// no copying
BackwardManager(BackwardManager const&) = delete;
BackwardManager(BackwardManager&&) = delete;
void operator=(BackwardManager const&) = delete;
};
} // namespace actors
} // namespace ddkit
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <ostream>
#include <memory>
namespace ddkit {
namespace actors {
class IActor;
typedef std::shared_ptr<IActor> ActorPtr;
struct CallbackInfo {
std::string serviceName; // serviceName of sending actor (client or service), this is always a real name
std::string sendingActor; // clientActorId or serviceActorId
std::string operationName; // rmodel-operationName, for example "ConfigAbc"
bool isFromClient;
bool isFromService;
bool isToClient;
bool isToService;
std::string clientName; // filled, if isFromClient, clientActorId, if user set clientName, clientName
int64_t timestampInMsSinceEpoch;
/// @brief Get informations about the current callback
/// This function should only be used inside a callback.
/// @return The current CallbackInfo object.
static CallbackInfo current();
friend std::ostream& operator<<(std::ostream& s, CallbackInfo const& rhs);
};
} // namespace actors
} // namespace ddkit
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include "SessionImpl.hpp"
#include "ddkit/utils/container.hpp"
#include "ddkit/actors/SessionImpl.hpp"
#include <memory>
#include <mutex>
#include <condition_variable>
namespace ddkit {
namespace actors {
class IActor;
typedef std::shared_ptr<IActor> ActorPtr;
class SessionImpl;
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
typedef std::weak_ptr<SessionImpl> SessionImplWeakPtr;
class IActor : public std::enable_shared_from_this<IActor> {
public:
virtual ~IActor();
SessionImplPtr sessionImpl();
bool isMonitor();
virtual void shutdown() = 0;
virtual bool isValid() = 0;
protected:
IActor(const SessionImplPtr& sessionImpl);
IActor() = delete;
IActor(IActor&) = delete;
IActor(IActor&&) = delete;
// todo nth: for which members exactly the syncing is needed? for now: try for all
std::recursive_mutex m_mutex;
std::condition_variable_any m_condition;
SessionImplWeakPtr m_sessionImplWeak;
};
} // namespace actors
} // namespace ddkit
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "ddkit/actors/ActorInfo.hpp"
namespace ddkit {
namespace actors {
/// @brief an ActorInfoDb must know about those services, which are 'important',
/// - that is: services local to the session, in/for which the actorInfoDb works.
/// - if some service is recognized twice in the network (normally a warning), and the local session is accountable
/// for it, the local process must die
/// so a session creating an ActorInfoDb must provide a function for up-to-date-knowledge about the local services
class ILocalServices {
public:
virtual bool isLocalService(ActorConfiguration config) = 0;
virtual ~ILocalServices() = default;
};
} // namespace actors
} // namespace ddkit
+90
View File
@@ -0,0 +1,90 @@
#pragma once
#include "ddkit/utils/Logger.hpp"
namespace ddkit {
namespace actors {
//
// IComponent, IObserver, ISender
//
// IObserver or ISender
class IComponent {
public:
virtual std::string module() = 0;
virtual bool isService() = 0; // caution: these method-names refer to Service and Client (Actor),
virtual bool isObserver() = 0; // in which the Sender/Observer live, not to IService/IClient!
// exceptionally we have (very lightweight) convenience-methods in the interface as well
inline bool isClient() { return !isService(); }
inline bool isSender() { return !isObserver(); }
virtual ~IComponent() = default;
};
class IObserver : public IComponent {
public:
// IComponent
std::string module() override = 0;
bool isService() override = 0;
bool isObserver() override { return true; }
virtual void clearCallbacks() {}
virtual ~IObserver() = default;
};
typedef std::shared_ptr<IObserver> IObserverPtr;
class ISender : public IComponent {
public:
// IComponent
std::string module() override = 0;
bool isService() override = 0;
bool isObserver() override { return false; }
virtual ~ISender() = default;
};
typedef std::shared_ptr<ISender> ISenderPtr;
//
// static_asserts to be included in every template-function
//
// observer w/o object - call checkTypeOfObserver<Observer>();
template <typename Observer>
void checkObserverType() {
DDKIT_LOG_TRACE;
static_assert(std::is_base_of<IObserver, Observer>::value, "Observer not derived from IObserver");
static_assert(!std::is_same<IObserver, Observer>::value, "Observer same class as IObserver");
}
// observer with object - simply call checkTypeOfObserver(observer);
template <typename Observer>
void checkTypeOfObserver(Observer* observer) {
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(observer);
checkObserverType<Observer>();
}
// sender w/o object - call checkSenderType<Sender>();
template <typename Sender>
void checkSenderType() {
DDKIT_LOG_TRACE;
static_assert(std::is_base_of<ISender, Sender>::value, "Sender not derived from ISender");
static_assert(!std::is_same<ISender, Sender>::value, "Sender same class as ISender");
static_assert(std::is_base_of<typename Sender::TypeUser, Sender>::value, "Sender not derived from TypeUser");
}
// sender with object - simply call checkTypeOfSender(sender);
template <typename Sender>
void checkTypeOfSender(Sender* sender) {
DDKIT_LOG_TRACE << DDKIT_LOG_VAR_VALUE(sender);
checkSenderType<Sender>();
}
} // namespace actors
} // namespace ddkit
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include "ddkit/actors/ActorInfo.hpp"
#include <memory>
namespace ddkit {
namespace actors {
class SessionImpl;
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
class MonitorSession final {
public:
MonitorSession(int domain);
~MonitorSession();
std::vector<ServiceInfo> findServices(const std::string& module);
std::vector<ClientInfo> findClients(const std::string& module);
std::vector<ClientInfo> findClients(const std::string& serviceName, const std::string& module);
private:
friend class SessionImpl;
SessionImplPtr m_sessionImpl;
SessionImpl& sessionImpl();
// no copying
MonitorSession(MonitorSession const&) = delete;
MonitorSession(MonitorSession&&) = delete;
void operator=(MonitorSession const&) = delete;
void operator=(MonitorSession&&) = delete;
};
} // namespace actors
} // namespace ddkit
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include "SessionImpl.hpp"
#include "ddkit/actors/IActor.hpp"
#include "ddkit/actors/MultiplexActorThread.hpp"
#include "ddkit/actors/SimpleActor.hpp"
#include <memory>
namespace ddkit {
namespace actors {
class MultiplexActor : public IActor {
public:
MultiplexActor(
const SessionImplPtr& sessionImpl,
bool isService,
const std::string& module,
const std::function<SimpleActorPtr(SessionImplPtr, const std::string&)>& createActor);
~MultiplexActor();
bool isValid() override;
void shutdown() override;
private:
std::vector<SimpleActorPtr> m_actors;
std::shared_ptr<MultiplexActorThread> m_threadActorMultiplex;
};
} // namespace actors
} // namespace ddkit
@@ -0,0 +1,48 @@
#pragma once
#include "ddkit/actors/SessionImpl.hpp"
#include "ddkit/base/Thread.hpp"
#include "ddkit/actors/ActorInfo.hpp"
#include <functional>
#include <vector>
namespace ddkit {
namespace actors {
class SessionImpl;
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
typedef std::weak_ptr<SessionImpl> SessionImplWeakPtr;
class SimpleActor;
typedef std::shared_ptr<SimpleActor> SimpleActorPtr;
class MultiplexActorThread : public base::Thread {
public:
MultiplexActorThread(
std::vector<SimpleActorPtr>& actors,
const SessionImplPtr& sessionImpl,
const std::function<SimpleActorPtr(SessionImplPtr, const std::string&)>& createActor,
const std::string& module,
bool isService);
~MultiplexActorThread();
// Thread
void run() override;
void shutdown();
private:
void addNewActors(std::vector<ActorInfo> const& actorsCurrent, SessionImplPtr sessionImpl);
void removeOldActors(std::vector<ActorInfo> const& actorsCurrent);
SessionImplWeakPtr m_sessionImpl;
std::function<SimpleActorPtr(SessionImplPtr, const std::string&)> m_createActor;
std::vector<SimpleActorPtr>& m_actors;
std::string m_module;
bool m_isService;
};
} // namespace actors
} // namespace ddkit
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include "ddkit/actors/ActorInfo.hpp"
#include <string>
#include <memory>
#include <vector>
namespace ddkit {
namespace actors {
class SessionImpl;
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
/// @brief Typically there should be only one Session per domain.
class Session final {
public:
Session(int domain);
~Session();
std::string sessionId();
std::vector<ServiceInfo> findServices(const std::string& module);
std::vector<ClientInfo> findClients(const std::string& module);
std::vector<ClientInfo> findClients(const std::string& serviceName, const std::string& module);
private:
friend class SessionImpl;
SessionImplPtr m_sessionImpl;
SessionImpl& sessionImpl();
Session() = delete;
// no copying
Session(Session const&) = delete;
Session(Session&&) = delete;
void operator=(Session const&) = delete;
void operator=(Session&&) = delete;
};
} // namespace actors
} // namespace ddkit
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include "ddkit/actors/Session.hpp"
#include "ddkit/actors/MonitorSession.hpp"
#include <unordered_map>
#include <memory>
#include <mutex>
namespace ddkit {
namespace actors {
class SessionFactory {
public:
/// @brief static
static SessionFactory& instance() {
static SessionFactory instance;
return instance;
}
std::shared_ptr<ddkit::actors::Session> getSession(int domain);
std::shared_ptr<ddkit::actors::MonitorSession> getMonitorSession(int domain);
bool isClean() const;
private:
template <typename T>
std::shared_ptr<T> get(int& domain, std::unordered_map<int, std::weak_ptr<T>>& map) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = map.find(domain);
if (it != map.end()) {
auto session_ptr = it->second.lock();
if (session_ptr) {
// Return existing session
return session_ptr;
}
}
// Create new session
auto session = std::shared_ptr<T>(
new T(domain),
[domain, &map, this](T* s) {
delete s;
cleanup(domain, map);
});
map[domain] = session;
return session;
}
template <typename T>
void cleanup(int domain, std::unordered_map<int, std::weak_ptr<T>>& map) {
// clean up
std::lock_guard<std::mutex> lock(m_mutex);
// We only erase if the weak pointer is expired, indicating no active shared_ptr exists.
auto it = map.find(domain);
if (it != map.end() && it->second.expired()) {
map.erase(it);
}
}
SessionFactory() = default;
SessionFactory(const SessionFactory&) = delete;
SessionFactory& operator=(const SessionFactory&) = delete;
std::unordered_map<int, std::weak_ptr<ddkit::actors::Session>> m_sessions;
std::unordered_map<int, std::weak_ptr<ddkit::actors::MonitorSession>> m_monitorSessions;
std::mutex m_mutex;
};
}
}
+134
View File
@@ -0,0 +1,134 @@
#pragma once
#include "ddkit/base/IConfig.hpp"
#include "ddkit/access/Dispatcher.hpp"
#include "ddkit/access/ICleanup.hpp"
#include "ddkit/actors/ActorInfoDbCaretaker.hpp"
#include "ddkit/actors/ActorInfoDb.hpp"
#include "ddkit/actors/ActorInfoWriter.hpp"
#include "ddkit/actors/Session.hpp"
#include "ddkit/actors/MonitorSession.hpp"
#include "ddkit/actors/ILocalServices.hpp"
#include <list>
#include <map>
#include <set>
namespace ddkit {
namespace actors {
class IActor;
typedef std::shared_ptr<IActor> ActorPtr;
typedef std::weak_ptr<IActor> ActorPtrWeak;
class SimpleActor;
typedef std::shared_ptr<SimpleActor> SimpleActorPtr;
class MultiplexActor;
typedef std::shared_ptr<MultiplexActor> MultiplexActorPtr;
class SessionImpl final : public std::enable_shared_from_this<SessionImpl>,
public access::ICleanup,
public ILocalServices {
public:
SessionImpl(base::IConfig& config, int domain, bool isMonitor);
~SessionImpl();
void init();
// create a new SessionImpl (even if another Session with same domain exists already)
static SessionImplPtr create(int domain, bool isMonitor);
// needed from generated createSome (api) (friend access on Session)
static SessionImplPtr getSessionImpl(Session& session);
static SessionImplPtr getSessionImpl(MonitorSession& session);
// getter
int domain();
access::Participant& participant();
std::string sessionId();
std::shared_ptr<access::Dispatcher> dispatcher();
ddkit_intern::Session sessionInfo();
bool isMonitor();
bool isCheckMostDerivedClassType();
int timeoutSecsWaitUntilConnected();
// key2actor
bool hasActor(const std::string& serviceName, bool isService, const std::string& module);
SimpleActorPtr findActor(const std::string& serviceName, bool isService, const std::string& module);
SimpleActorPtr createActor(const std::string& serviceName, bool isService, const std::string& module);
MultiplexActorPtr createActorMultiplex(
bool isService,
const std::string& module,
const std::function<SimpleActorPtr(SessionImplPtr, const std::string&)>& createActor);
SimpleActorPtr createOrFindActor(const std::string& serviceName, bool isService, const std::string& module);
// ICleanup
void cleanup() override; // called from dispatcher regularly for removing non-referenced actors
bool isShutdownRequested() override;
// ids for Actors
int nextSequenceId() { return m_nextSequenceId++; }
// ActorInfo (sending to dds - actor-specific-part)
void publishActorInfo(ddkit_intern::ActorInfo actorInfo);
void disposeActorInfo(ddkit_intern::ActorInfo actorInfo);
// ActorInfo (using dds-meta-info)
std::vector<ServiceInfo> findRunningServices(const std::string& module);
std::vector<ServiceInfo> findRunningServices(const std::string& serviceName, const std::string& module); // max 1
std::vector<ClientInfo> findRunningClients(const std::string& module);
std::vector<ClientInfo> findRunningClients(const std::string& serviceName, const std::string& module);
// ILocalServices
bool isLocalService(ActorConfiguration config); // called from ActorInfoDb
std::string clientActorId2clientName(const std::string& clientActorId); // access meta-infos for callbackInfo
void shutdownActors();
void shutdownMultiplexActors();
void requestShutdown();
void requestCleanup();
void removeMultiplexActor(std::shared_ptr<IActor> multiplexActor);
private:
std::recursive_mutex m_mutex;
std::condition_variable_any m_condition;
bool m_isMonitor;
int m_domain;
access::Participant m_participant;
std::string m_sessionId; // identifies this session globally!
int m_nextSequenceId; // identifiying-addition for Actors
std::shared_ptr<access::Dispatcher> m_dispatcher;
std::vector<SimpleActorPtr> m_simpleActors; // 'normal'-actors (including internal actors of multiplex)
std::vector<MultiplexActorPtr> m_multiplexActors; // 'multiplex'-actors (have no serviceName for key, thus extra)
// ActorInfo (sending to dds - session-specific-part)
ddkit_intern::Process m_process;
ddkit_intern::Session m_sessionInfo;
ActorInfoWriter m_actorInfoWriter;
std::vector<ActorConfiguration> m_localServices; // log which services accountable for
// ActorInfo (reading from dds - monitor-intern-part)
ActorInfoDb m_actorInfoDb;
ActorInfoDbCaretaker m_ActorInfoDbCaretaker;
bool m_isCheckMostDerivedClassType;
int m_timeoutSecsWaitUntilConnected;
std::atomic<bool> m_shutdownRequested;
// no copying
SessionImpl(SessionImpl const&) = delete;
SessionImpl(SessionImpl&&) = delete;
void operator=(SessionImpl const&) = delete;
};
} // namespace actors
} // namespace ddkit
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include "ddkit/base/ThreadInline.hpp"
#include "ddkit/access/ConfigLoaderDds.hpp"
#include "ddkit/actors/CallbackInfo.hpp"
#include <memory>
#include <mutex>
#include <vector>
#include <map>
namespace ddkit {
namespace actors {
class SessionImpl;
typedef std::shared_ptr<SessionImpl> SessionImplPtr;
typedef std::weak_ptr<SessionImpl> SessionImplWeakPtr;
class SessionManager {
public:
static SessionManager& instance();
SessionImplPtr createSessionImpl(int domain, bool isMonitor); // called from SessionImpl
SessionImplPtr findSession(const std::string& sessionId); // called from BackwardManager
void removeExpiredSessions(); // called from BackwardManager, MonitorSession, Session
void removeSession(const std::string& sessionId);
void setCallbackInfo(const CallbackInfo& callbackInfo); // called from ActorImpl
void resetCallbackInfo(); // called from ActorImpl, generated Code
CallbackInfo callbackInfo(); // called from ActorImpl, BackwardManager, CallbackInfo, generated Code
bool isClean() const;
private:
std::shared_ptr<access::ConfigLoaderDds> m_configLoaderDds;
std::mutex m_sessionMutex;
std::map<std::string, SessionImplWeakPtr> m_sessionId2sessionImpl; // holding map for sessions
std::mutex m_callbackMutex;
std::map<std::string, CallbackInfo> m_threadId2callbackInfo; // per thread (typically one entry - while callback)
SessionManager();
~SessionManager();
bool hasSession(const std::string& sessionId);
bool hasSessions();
// no copying
SessionManager(SessionManager const&) = delete;
SessionManager(SessionManager&&) = delete;
void operator=(SessionManager const&) = delete;
};
} // namespace actors
} // namespace ddkit
+213
View File
@@ -0,0 +1,213 @@
#pragma once
#include "ddkit/utils/assert.hpp"
#include "ddkit/access/TopicPoolRead.hpp"
#include "ddkit/access/TopicPoolWrite.hpp"
#include "ddkit/actors/CallbackInfo.hpp"
#include "ddkit/actors/IActor.hpp"
#include "ddkit/actors/SessionImpl.hpp"
#include "ddkit/idls/ActorInfo.hpp"
#include "ddkit/actors/Key.hpp"
#include "ddkit/utils/CallbackWrapper.hpp"
#include <string>
#include <map>
namespace ddkit {
namespace actors {
class SimpleActor : public IActor {
public:
SimpleActor(const SessionImplPtr& sessionImpl,
const std::string& serviceName,
bool isService,
const std::string& module);
~SimpleActor();
bool hasObserver();
bool hasSender();
access::TopicPoolRead& topicPoolRead();
access::TopicPoolWrite& topicPoolWrite();
std::string moduleName() const;
bool isService() const;
int domain() const;
std::string serviceName() const;
ActorConfiguration config() const;
std::string actorId() const;
bool operator==(const SimpleActor& other) const;
void setClientName(const std::string& clientName);
void waitUntilConnected();
void addConnectCheck(access::IConnectCheckPtr connectCheck);
// template-class-parameters Observer and Sender in the following methods must be the 'reader-class'
// respectively the 'writer-class' of one of the rmodel-modules. They are called Observer and Sender
// in the corresponding namespace and inherit the interface IObserver/ISender. They define a typedef TypeUser
// to refer to the API-Interface-Type IClient/IService. Sender also inherits its TypeUser-Type
/// @brief - needed for access from generated Service/Client, to call write-stuff
template <typename Sender>
ISenderPtr sender() {
DDKIT_LOG_TRACE;
checkSenderType<Sender>();
if (hasSender()) {
std::shared_ptr<Sender> sender = std::dynamic_pointer_cast<Sender>(m_sender); // Sender inherits ISender
if (sender) {
checkTypeOfSender(sender.get());
return sender;
}
}
return nullptr;
}
ISenderPtr sender() {
return m_sender;
}
IObserverPtr observer() {
return m_observer;
}
bool hasSession() {
return !m_sessionImplWeak.expired();
}
template <typename Observer>
IObserverPtr createObserver(typename Observer::TypeUser& callbacks, const std::vector<std::string>& methods) {
ddkit::log::info() << "Create observer";
SessionImplPtr sessionImpl = m_sessionImplWeak.lock();
if (!sessionImpl) {
throw std::runtime_error("Failure locking std::weak_ptr<SessionImpl> in ActorImpl");
}
checkObserverType<Observer>();
typename Observer::TypeUser* userCallback = &callbacks; // (keep * inside ... else problems with capturing)
// insert observer
DDKIT_THROW_ON_FALSE_INFO(
!hasObserver(),
"Inserting an observer to an actor already containing one."
"Called ObsFactory::add() twice? (same serviceName + domain)");
m_observer = std::make_shared<Observer>(*this, m_topicPoolRead, methods, userCallback);
DDKIT_THROW_ON_FALSE_INFO(hasObserver(), "creation of observer failed");
// update actorInfo
if (m_actorInfo.isReading()) {
ddkit::log::warn() << "SimpleActor::createObserver: " << "actor is already reading";
}
m_actorInfo.isReading() = true;
m_actorInfo.openReaders() = methods; // only vectors on dds
sessionImpl->publishActorInfo(m_actorInfo);
return m_observer;
}
template <typename Observer>
IObserverPtr createObserver(std::map<std::string, std::vector<ddkit::callback::Base*>> callbacks, const std::vector<std::string> methods) {
ddkit::log::info() << "Create observer";
SessionImplPtr sessionImpl = m_sessionImplWeak.lock();
if (!sessionImpl) {
throw std::runtime_error("Failure locking std::weak_ptr<SessionImpl> in ActorImpl");
}
checkObserverType<Observer>();
// insert observer
DDKIT_THROW_ON_FALSE_INFO(
!hasObserver(),
"Inserting an observer to an actor already containing one."
"Called ObsFactory::add() twice? (same serviceName + domain)");
m_observer = std::make_shared<Observer>(*this, m_topicPoolRead, methods, callbacks);
DDKIT_THROW_ON_FALSE_INFO(hasObserver(), "creation of observer failed");
// update actorInfo
if(m_actorInfo.isReading()) {
ddkit::log::warn() << "SimpleActor::createObserver: actor is already reading";
}
m_actorInfo.isReading() = true;
m_actorInfo.openReaders() = methods; // only vectors on dds
sessionImpl->publishActorInfo(m_actorInfo);
return m_observer;
}
template <typename Sender>
ISenderPtr createSender(const std::vector<std::string>& methods) {
ddkit::log::info() << "Create sender";
SessionImplPtr sessionImpl = m_sessionImplWeak.lock();
if (!sessionImpl) {
throw std::runtime_error("Failure locking std::weak_ptr<SessionImpl> in ActorImpl");
}
checkSenderType<Sender>();
DDKIT_THROW_ON_FALSE_INFO(
!hasSender(),
"Inserting a sender to an actor already containing one. "
"Called Factory::create() twice? (same serviceName + domain)");
m_sender = std::make_shared<Sender>(*this, m_topicPoolWrite);
Sender* sender2 = dynamic_cast<Sender*>(m_sender.get());
checkTypeOfSender(sender2);
DDKIT_THROW_ON_FALSE(sender2);
DDKIT_THROW_ON_FALSE(hasSender());
// update actorInfo
if (m_actorInfo.isWriting()) {
ddkit::log::warn() << "SimpleActor::createSender: " << "actor is already writing";
}
m_actorInfo.isWriting() = true;
m_actorInfo.openWriters() = methods; // only vectors on dds
sessionImpl->publishActorInfo(m_actorInfo);
return m_sender;
}
void discardSender();
void discardObserver();
bool isValid() override;
void shutdown() override;
bool shutdownRequested();
CallbackInfo callbackInfoBase();
CallbackInfo callbackInfo();
void setCallbackInfo(CallbackInfo callbackInfo);
void resetCallbackInfo();
private:
ddkit_intern::ActorInfo m_actorInfo;
access::IQosStrategyPtr m_qosStrategy;
access::ITopicStrategyPtr m_topicStrategy;
access::TopicPoolRead m_topicPoolRead;
access::TopicPoolWrite m_topicPoolWrite;
std::vector<access::IConnectCheckPtr> m_connectCheckSet;
IObserverPtr m_observer; // or nullptr, if none
ISenderPtr m_sender; // or nullptr, if none
CallbackInfo m_callbackInfoBase;
std::atomic<bool> m_shutdownRequested;
};
} // namespace actors
} // namespace ddkit
+77
View File
@@ -0,0 +1,77 @@
#pragma once
#include "ddkit/base/IConfig.hpp"
#include <nlohmann/json.hpp>
#include <stdexcept>
#include <vector>
#include <memory>
namespace ddkit {
namespace base {
class Config : public IConfig {
public:
// as both ctor-params are strings, make constructor-calls disambiguous:
struct Text {
explicit Text(const std::string& text)
: m_text(text) {}
std::string m_text;
};
struct Filename {
explicit Filename(const std::string& filename)
: m_filename(filename) {}
std::string m_filename;
};
class FileNotFound : public std::runtime_error {
public:
FileNotFound(const std::string& filename) : std::runtime_error("could not open file \"" + filename + "\""){}
};
Config();
Config(const nlohmann::json&);
Config(const Text& text); // call: Config config((Config::Text("{ abc = 17 }")));
Config(const Filename& filename);
Config(const Config&);
void operator=(Config const&);
// IConfig
bool hasKey(const std::string& key) const override;
std::string getStringValue(const std::string& key) const override;
int getIntValue(const std::string& key) const override;
int64_t getInt64Value(const std::string& key) const override;
bool getBoolValue(const std::string& key) const override;
// todo array into IConfig?
int getArraySize(const std::string& key) const;
// no template-getter any more (error-prone in conjunction with type-casts)
// no default-getter any more (error-prone in conjunction with typos)
// no optional-getter any more (too much tmsif-API-logic, might be useful in other place)
bool isInt64Value(const std::string& key) const; // int or int64
bool isBoolValue(const std::string& key) const;
bool isStringValue(const std::string& key) const;
bool isArrayValue(const std::string& key) const;
bool isListValue(const std::string& key) const; // has subKeys
std::vector<std::string> getSubKeys(const std::string& key) const;
Config getSubConfig(const std::string& key) const;
operator std::string() const;
private:
static nlohmann::json::json_pointer keyToJsonPointer(const std::string& key);
nlohmann::json getValue(const std::string& key) const;
bool hasKey(const nlohmann::json&, const std::string& key) const;
bool hasKey(const nlohmann::json& jsonObj, const nlohmann::json::json_pointer& jsonPtr) const;
nlohmann::json m_json;
};
} // namespace base
} // namespace ddkit
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "ddkit/base/Config.hpp"
namespace ddkit {
namespace access {
class ConfigLoaderDds;
}
namespace base {
/// @brief class "ConfigLoader"
/// - it holds the config-File of the application and sets up the logger
/// Hold by ConfigLoaderDds
class ConfigLoader final {
public:
ConfigLoader(const std::string& configFile);
~ConfigLoader();
Config& config() { return m_config; }
private:
std::string m_programName;
Config m_config;
// no copying
ConfigLoader(ConfigLoader const&) = delete;
ConfigLoader(ConfigLoader&&) = delete;
void operator=(ConfigLoader const&) = delete;
void operator=(ConfigLoader&&) = delete;
};
} // namespace base
} // namespace ddkit
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include "ddkit/base/Config.hpp"
#include "ddkit/base/IConfigWrite.hpp"
#include <set>
#include <map>
namespace ddkit {
namespace base {
/// @brief ConfigRw (ReadWrite) is constructed with a normal Config (read, from a file) and enables overwrite of keys as well.
/// additionally it may be checked, which keys are allowed
class ConfigRw : public IConfig,
public IConfigWrite {
public:
ConfigRw();
ConfigRw(Config& config);
ConfigRw(const ConfigRw&);
void operator=(const ConfigRw&);
// IConfig
bool hasKey(const std::string& key) const override;
std::string getStringValue(const std::string& key) const override;
int getIntValue(const std::string& key) const override;
int64_t getInt64Value(const std::string& key) const override;
bool getBoolValue(const std::string& key) const override;
// IConfigWrite
void setStringValue(const std::string& key, const std::string& value) override;
void setIntValue(const std::string& key, int value) override;
void setInt64Value(const std::string& key, int64_t value) override;
void setBoolValue(const std::string& key, bool value) override;
// activate checks. i.e. foo.bar -> section foo and key bar
void registerKnownConfigKey(
const std::string& section,
const std::string& key);
void checkConfig() const; // check in file (only for corresponding top-level)
private:
// the 'real' BaseConfig (ConfigFile from ConfigLoader)
Config m_config;
// the overwritten key-values
std::vector<std::string> m_keys;
std::map<std::string, std::string> m_key2stringValue;
std::map<std::string, int> m_key2intValue;
std::map<std::string, int64_t> m_key2int64Value;
std::map<std::string, bool> m_key2boolValue;
// keys allowed
std::map<std::string, std::vector<std::string>> m_knownKeysMap;
void checkKey(const std::string& key) const;
void checkConfig(const std::string& prefix) const; // check in file
};
} // namespace base
} // namespace ddkit
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <string>
namespace ddkit {
namespace base {
class IConfig {
public:
virtual ~IConfig() = default;
virtual bool hasKey(const std::string& key) const = 0;
// getters which throw if the key does not exist
virtual std::string getStringValue(const std::string& key) const = 0;
virtual int getIntValue(const std::string& key) const = 0;
virtual int64_t getInt64Value(const std::string& key) const = 0;
virtual bool getBoolValue(const std::string& key) const = 0;
// getters which return a default if the key does not exist
std::string getStringValue(const std::string& key, const std::string& defaultValue) const {
if (hasKey(key)) return getStringValue(key);
return defaultValue;
}
int getIntValue(const std::string& key, int defaultValue) const {
if (hasKey(key)) return getIntValue(key);
return defaultValue;
}
int64_t getInt64Value(const std::string& key, int64_t defaultValue) const {
if (hasKey(key)) return getInt64Value(key);
return defaultValue;
}
bool getBoolValue(const std::string& key, bool defaultValue) const {
if (hasKey(key)) return getBoolValue(key);
return defaultValue;
}
};
} // namespace base
} // namespace ddkit
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include <string>
namespace ddkit {
namespace base {
class IConfigWrite {
public:
virtual void setStringValue(const std::string& key, const std::string& value) = 0;
virtual void setIntValue(const std::string& key, int value) = 0;
virtual void setInt64Value(const std::string& key, int64_t value) = 0;
virtual void setBoolValue(const std::string& key, bool value) = 0;
virtual ~IConfigWrite() = default;
};
} // namespace base
} // namespace ddkit
+117
View File
@@ -0,0 +1,117 @@
#pragma once
#include <sstream>
#include <vector>
#include <exception>
namespace ddkit {
namespace base {
/// @brief exception class for serialization errors
/// emitted for any errors encouted during parsing
/// for details refere to what() message
class SerializationError : public std::exception {
public:
SerializationError(const std::string& message) : m_message(message) {
}
virtual const char* what() const noexcept override {
return m_message.c_str();
}
private:
const std::string m_message;
};
/// @brief simple serialization like stringstream
/// - serialized format is a string, readable
/// - may be deserialized with same operator-calling-pattern of types on another instance
/// mixed calls to serializing and deserializing on same object -> undefined behaviour
class Serialization {
std::ostringstream m_os;
std::istringstream m_is;
// bool m_isSerializing; // todo nth check?
// bool m_isDeserializing;
public:
// serializing
Serialization();
std::string str();
// deserializing
explicit Serialization(const std::string& text);
bool isEnd();
// bool
Serialization& operator<<(bool rhs);
Serialization& operator>>(bool& rhs);
// int char
Serialization& operator<<(uint8_t rhs);
Serialization& operator>>(uint8_t& rhs);
Serialization& operator<<(uint16_t rhs);
Serialization& operator>>(uint16_t& rhs);
Serialization& operator<<(uint32_t rhs);
Serialization& operator>>(uint32_t& rhs);
Serialization& operator<<(uint64_t rhs);
Serialization& operator>>(uint64_t& rhs);
Serialization& operator<<(int8_t rhs);
Serialization& operator>>(int8_t& rhs);
Serialization& operator<<(int16_t rhs);
Serialization& operator>>(int16_t& rhs);
Serialization& operator<<(int32_t rhs);
Serialization& operator>>(int32_t& rhs);
Serialization& operator<<(int64_t rhs);
Serialization& operator>>(int64_t& rhs);
Serialization& operator<<(char rhs);
Serialization& operator>>(char& rhs);
// float double
Serialization& operator<<(double rhs);
Serialization& operator>>(double& rhs);
Serialization& operator<<(float rhs);
Serialization& operator>>(float& rhs);
// string
Serialization& operator<<(const std::string& rhs);
Serialization& operator>>(std::string& rhs);
// vector
template <typename T>
Serialization& operator<<(std::vector<T> const& rhs) {
*this << rhs.size();
for (T const& t : rhs) {
*this << t;
}
return *this;
}
template <typename T>
Serialization& operator>>(std::vector<T>& rhs) {
rhs.clear();
int size = getSize();
for (int i = 0; i < size; ++i) {
T t;
*this >> t;
rhs.push_back(t);
}
return *this;
}
private:
std::string readBytes(int size);
void expectAndSkipComma();
int getSize();
};
} // namespace base
} // namespace ddkit
+58
View File
@@ -0,0 +1,58 @@
#pragma once
#include <condition_variable>
#include <memory>
#include <string>
#include <mutex>
#include <thread>
namespace ddkit {
namespace base {
/// @brief wrapper for std::thread, including
/// - clean synchronized start/stop/stopCommanded-mechanism
/// - tracing with threadname, exception-logging on outermost level
class Thread {
public:
/// @param name 6-char-thread-name
Thread(const std::string& name);
virtual ~Thread();
void start();
// void stop(); // call stopAndJoin instead
void stopAndJoin();
bool isActive() const;
void waitForStopCommanded();
bool stopCommanded() const;
private:
std::string m_name;
std::unique_ptr<std::thread> m_thread;
bool m_threadExecutionActive;
std::mutex m_mutexStart;
std::condition_variable m_threadStarted;
bool m_hasStarted;
std::mutex m_mutexStop;
std::condition_variable m_threadStopped;
bool m_stopCommanded;
virtual void run();
virtual void onStop();
void startUp();
void waitForStarted();
virtual void waitForReadyIf();
// no copying
Thread(Thread const&) = delete;
Thread(Thread&&) = delete;
void operator=(Thread const&) = delete;
};
} // namespace base
} // namespace ddkit
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "ddkit/base/Thread.hpp"
#include <functional>
namespace ddkit {
namespace base {
class ThreadInline final : public Thread {
public:
ThreadInline(const std::string& name, const std::function<void()>& function);
~ThreadInline() override;
private:
std::function<void()> m_function;
void run() override;
ThreadInline(ThreadInline const&) = delete;
void operator=(ThreadInline const&) = delete;
};
} // namespace base
} // namespace ddkit
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "ddkit/base/Thread.hpp"
namespace ddkit {
namespace base {
/// @brief ThreadSync may be used instead of Thread, if 'start()' shall be 'synchronous', that is
/// - the os-thread, which is calling 'start()' on this obj, is blocked until
/// - the new os-thread is created and the intern-thread-function was started
/// - the overridden 'run()'-method (Derivee from ThreadSync) is started
/// - the implementation of that 'run'-method decided to call 'ready()'
/// - (as first command, or after some initialization-steps, which went for some reason not in ctor, but run)
class ThreadSync : public Thread {
public:
ThreadSync(const std::string& name);
virtual ~ThreadSync() override;
protected:
void ready();
private:
std::recursive_mutex m_mutex;
std::condition_variable_any m_condition;
bool m_isReady; // did the thread call "ready()" for signaling "fully" starting up?
void waitForReadyIf() override; // called by Thread
ThreadSync(ThreadSync const&) = delete;
void operator=(ThreadSync const&) = delete;
};
} // namespace base
} // namespace ddkit
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <string>
#define DDKIT_VERSION_MAJOR 3
#define DDKIT_VERSION_MINOR 9
#define DDKIT_VERSION_PATCH 0
#define DDKIT_VERSION_ATLEAST(major, minor, patch) ((major >= DDKIT_VERSION_MAJOR) && (minor >= DDKIT_VERSION_MINOR) && (patch >= DDKIT_VERSION_PATCH))
namespace ddkit {
namespace build_info {
namespace version {
const std::string string = "3.9.0";
const int major = 3;
const int minor = 9;
const int patch = 0;
}
namespace conan {
const std::string channel = "stable";
const std::string package = "98937235a8ae97010a6498036572bf0d26e6de10";
}
namespace dds {
const std::string vendor = "cyclone";
const std::string vendor_version = "20250204-conan-recipe-v3";
}
}
}
+78
View File
@@ -0,0 +1,78 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GENERATED CODE - do not edit (Generated by ddkit/genVendorWrap)
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this file (ActorInfo.hpp) wraps the corresponding vendor-generated C++-Header.
// include it via -> #include "ddkit/idls/ActorInfo.hpp"
#pragma once
#include <ddkit/utils/Logger.hpp>
#include <ddkit/utils/string.hpp>
#include <ddkit/utils/container.hpp>
// dds-vendor-specific header
#ifdef _WIN32
#pragma warning(push, 0)
#endif
#ifdef DDS_VENDOR_OPENSPLICE
#include <ddkit/idls/vendor/ActorInfo_DCPS.hpp>
#else
#include <ddkit/idls/vendor/ActorInfo.hpp>
#endif
#ifdef _WIN32
#pragma warning(pop)
#endif
// define ostream-operators (<<) for vendors not defining them theirselves
#if defined(DDS_VENDOR_OPENSPLICE)
namespace ddkit_intern {
using ::ddkit::utils::container::operator<<;
inline std::ostream& operator<<(std::ostream& s, Process const& rhs)
{
return s << "["
<< "processId: " << (rhs.processId())
<< ", hostName: " << (rhs.hostName())
<< ", procName: " << (rhs.procName())
<< "]";
}
using ::ddkit::utils::container::operator<<;
inline std::ostream& operator<<(std::ostream& s, Session const& rhs)
{
return s << "["
<< "sessionId: " << (rhs.sessionId())
<< ", process: " << (rhs.process())
<< "]";
}
using ::ddkit::utils::container::operator<<;
inline std::ostream& operator<<(std::ostream& s, ActorInfo const& rhs)
{
return s << "["
<< "actorId: " << (rhs.actorId())
<< ", session: " << (rhs.session())
<< ", sequenceId: " << (rhs.sequenceId())
<< ", serviceName: " << (rhs.serviceName())
<< ", domain: " << static_cast<int16_t>(rhs.domain())
<< ", isService: " << (rhs.isService())
<< ", moduleName: " << (rhs.moduleName())
<< ", isReading: " << (rhs.isReading())
<< ", openReaders: " << (rhs.openReaders())
<< ", isWriting: " << (rhs.isWriting())
<< ", openWriters: " << (rhs.openWriters())
<< ", clientName: " << (rhs.clientName())
<< "]";
}
} // ddkit_intern
#endif // defined(DDS_VENDOR_OPENSPLICE)
+58
View File
@@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GENERATED CODE - do not edit (Generated by ddkit/genVendorWrap)
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this file (TestTopic.hpp) wraps the corresponding vendor-generated C++-Header.
// include it via -> #include "ddkit/idls/TestTopic.hpp"
#pragma once
#include <ddkit/utils/Logger.hpp>
#include <ddkit/utils/string.hpp>
#include <ddkit/utils/container.hpp>
// dds-vendor-specific header
#ifdef _WIN32
#pragma warning(push, 0)
#endif
#ifdef DDS_VENDOR_OPENSPLICE
#include <ddkit/idls/vendor/TestTopic_DCPS.hpp>
#else
#include <ddkit/idls/vendor/TestTopic.hpp>
#endif
#ifdef _WIN32
#pragma warning(pop)
#endif
// define ostream-operators (<<) for vendors not defining them theirselves
#if defined(DDS_VENDOR_OPENSPLICE)
namespace ddkit_intern {
using ::ddkit::utils::container::operator<<;
inline std::ostream& operator<<(std::ostream& s, TestTopic const& rhs)
{
return s << "["
<< "id: " << (rhs.id())
<< ", val: " << (rhs.val())
<< "]";
}
using ::ddkit::utils::container::operator<<;
inline std::ostream& operator<<(std::ostream& s, TestTopic2 const& rhs)
{
return s << "["
<< "id: " << (rhs.id())
<< ", val: " << (rhs.val())
<< "]";
}
} // ddkit_intern
#endif // defined(DDS_VENDOR_OPENSPLICE)
File diff suppressed because it is too large. Load diff
+548
View File
@@ -0,0 +1,548 @@
/****************************************************************
Generated by Eclipse Cyclone DDS IDL to CXX Translator
File name: /data/jenkins/workspace/workspace/ddkit_release_v3-9-x/cnn_l_0/.conan/data/ddkit/3.9.0/jenkins/stable/build/98937235a8ae97010a6498036572bf0d26e6de10/src/ddkit/idls/TestTopic.idl
Source: TestTopic.hpp
Cyclone DDS: v0.11.0
*****************************************************************/
#ifndef DDSCXX_TESTTOPIC_HPP_5D6BACE0D1D9ADC0287C638316554B9B
#define DDSCXX_TESTTOPIC_HPP_5D6BACE0D1D9ADC0287C638316554B9B
#include <utility>
#include <ostream>
#include <cstdint>
namespace ddkit_intern
{
class TestTopic
{
private:
int32_t id_ = 0;
int32_t val_ = 0;
public:
TestTopic() = default;
explicit TestTopic(
int32_t id,
int32_t val) :
id_(id),
val_(val) { }
int32_t id() const { return this->id_; }
int32_t& id() { return this->id_; }
void id(int32_t _val_) { this->id_ = _val_; }
int32_t val() const { return this->val_; }
int32_t& val() { return this->val_; }
void val(int32_t _val_) { this->val_ = _val_; }
bool operator==(const TestTopic& _other) const
{
(void) _other;
return id_ == _other.id_ &&
val_ == _other.val_;
}
bool operator!=(const TestTopic& _other) const
{
return !(*this == _other);
}
};
std::ostream& operator<<(std::ostream& os, TestTopic const& rhs);
class TestTopic2
{
private:
int32_t id_ = 0;
int32_t val_ = 0;
public:
TestTopic2() = default;
explicit TestTopic2(
int32_t id,
int32_t val) :
id_(id),
val_(val) { }
int32_t id() const { return this->id_; }
int32_t& id() { return this->id_; }
void id(int32_t _val_) { this->id_ = _val_; }
int32_t val() const { return this->val_; }
int32_t& val() { return this->val_; }
void val(int32_t _val_) { this->val_ = _val_; }
bool operator==(const TestTopic2& _other) const
{
(void) _other;
return id_ == _other.id_ &&
val_ == _other.val_;
}
bool operator!=(const TestTopic2& _other) const
{
return !(*this == _other);
}
};
std::ostream& operator<<(std::ostream& os, TestTopic2 const& rhs);
} //namespace ddkit_intern
#include "dds/topic/TopicTraits.hpp"
#include "org/eclipse/cyclonedds/topic/datatopic.hpp"
namespace org {
namespace eclipse {
namespace cyclonedds {
namespace topic {
template <> constexpr const char* TopicTraits<::ddkit_intern::TestTopic>::getTypeName()
{
return "ddkit_intern::TestTopic";
}
#ifdef DDSCXX_HAS_TYPELIB
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic>::type_map_blob_sz() { return 242; }
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic>::type_info_blob_sz() { return 100; }
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic>::type_map_blob() {
alignas(4) static const uint8_t blob[] = {
0x4b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b,
0x65, 0x3d, 0x6a, 0xef, 0x9a, 0xac, 0x32, 0x00, 0x33, 0x00, 0x00, 0x00, 0xf1, 0x51, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0xb8, 0x0b, 0xb7, 0x74, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x3a, 0x6d, 0x02, 0x84, 0x00,
0x76, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xd7, 0xaf, 0xad, 0x2b, 0xe3, 0xe9, 0xf7,
0x20, 0xd5, 0xec, 0x5e, 0xad, 0xb6, 0x6d, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xf2, 0x51, 0x01, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0x64, 0x6b, 0x69,
0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x3a, 0x3a, 0x54, 0x65, 0x73, 0x74, 0x54, 0x6f,
0x70, 0x69, 0x63, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x64, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x76, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0xf2, 0xd7, 0xaf, 0xad, 0x2b, 0xe3, 0xe9, 0xf7, 0x20, 0xd5, 0xec, 0x5e,
0xad, 0xb6, 0x6d, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65, 0x3d, 0x6a, 0xef, 0x9a,
0xac, 0x32, };
return blob;
}
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic>::type_info_blob() {
alignas(4) static const uint8_t blob[] = {
0x60, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65, 0x3d, 0x6a, 0xef,
0x9a, 0xac, 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0xf2, 0xd7, 0xaf, 0xad, 0x2b, 0xe3, 0xe9, 0xf7, 0x20, 0xd5, 0xec, 0x5e,
0xad, 0xb6, 0x6d, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, };
return blob;
}
#endif //DDSCXX_HAS_TYPELIB
template <> constexpr const char* TopicTraits<::ddkit_intern::TestTopic2>::getTypeName()
{
return "ddkit_intern::TestTopic2";
}
#ifdef DDSCXX_HAS_TYPELIB
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic2>::type_map_blob_sz() { return 246; }
template<> constexpr unsigned int TopicTraits<::ddkit_intern::TestTopic2>::type_info_blob_sz() { return 100; }
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic2>::type_map_blob() {
alignas(4) static const uint8_t blob[] = {
0x4b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b,
0x65, 0x3d, 0x6a, 0xef, 0x9a, 0xac, 0x32, 0x00, 0x33, 0x00, 0x00, 0x00, 0xf1, 0x51, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0xb8, 0x0b, 0xb7, 0x74, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x3a, 0x6d, 0x02, 0x84, 0x00,
0x7a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xce, 0x3c, 0x46, 0x72, 0x20, 0xd5, 0x19,
0x8d, 0x0a, 0x7c, 0x19, 0x4d, 0xa2, 0xc7, 0x00, 0x62, 0x00, 0x00, 0x00, 0xf2, 0x51, 0x01, 0x00,
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x64, 0x64, 0x6b, 0x69,
0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x3a, 0x3a, 0x54, 0x65, 0x73, 0x74, 0x54, 0x6f,
0x70, 0x69, 0x63, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00,
0x69, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xce, 0x3c, 0x46, 0x72, 0x20, 0xd5, 0x19,
0x8d, 0x0a, 0x7c, 0x19, 0x4d, 0xa2, 0xc7, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65,
0x3d, 0x6a, 0xef, 0x9a, 0xac, 0x32, };
return blob;
}
template<> inline const uint8_t * TopicTraits<::ddkit_intern::TestTopic2>::type_info_blob() {
alignas(4) static const uint8_t blob[] = {
0x60, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0xf1, 0x16, 0xdb, 0x53, 0x06, 0x8c, 0x26, 0x7b, 0x65, 0x3d, 0x6a, 0xef,
0x9a, 0xac, 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0xf2, 0xce, 0x3c, 0x46, 0x72, 0x20, 0xd5, 0x19, 0x8d, 0x0a, 0x7c, 0x19,
0x4d, 0xa2, 0xc7, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, };
return blob;
}
#endif //DDSCXX_HAS_TYPELIB
} //namespace topic
} //namespace cyclonedds
} //namespace eclipse
} //namespace org
namespace dds {
namespace topic {
template <>
struct topic_type_name<::ddkit_intern::TestTopic>
{
static std::string value()
{
return org::eclipse::cyclonedds::topic::TopicTraits<::ddkit_intern::TestTopic>::getTypeName();
}
};
template <>
struct topic_type_name<::ddkit_intern::TestTopic2>
{
static std::string value()
{
return org::eclipse::cyclonedds::topic::TopicTraits<::ddkit_intern::TestTopic2>::getTypeName();
}
};
}
}
REGISTER_TOPIC_TYPE(::ddkit_intern::TestTopic)
REGISTER_TOPIC_TYPE(::ddkit_intern::TestTopic2)
namespace org{
namespace eclipse{
namespace cyclonedds{
namespace core{
namespace cdr{
template<>
const propvec &get_type_props<::ddkit_intern::TestTopic>();
namespace {
static const volatile propvec &properties___ddkit_intern__TestTopic = get_type_props<::ddkit_intern::TestTopic>();
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool write(T& streamer, const ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!write(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!write(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool write(S& str, const ::ddkit_intern::TestTopic& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
str.set_mode(cdr_stream::stream_mode::write, key);
return write(str, instance, props.data());
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool read(T& streamer, ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!read(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!read(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool read(S& str, ::ddkit_intern::TestTopic& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
str.set_mode(cdr_stream::stream_mode::read, key);
return read(str, instance, props.data());
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool move(T& streamer, const ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!move(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!move(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool move(S& str, const ::ddkit_intern::TestTopic& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
str.set_mode(cdr_stream::stream_mode::move, key);
return move(str, instance, props.data());
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool max(T& streamer, const ::ddkit_intern::TestTopic& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!max(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!max(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool max(S& str, const ::ddkit_intern::TestTopic& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic>();
str.set_mode(cdr_stream::stream_mode::max, key);
return max(str, instance, props.data());
}
template<>
const propvec &get_type_props<::ddkit_intern::TestTopic2>();
namespace {
static const volatile propvec &properties___ddkit_intern__TestTopic2 = get_type_props<::ddkit_intern::TestTopic2>();
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool write(T& streamer, const ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!write(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!write(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool write(S& str, const ::ddkit_intern::TestTopic2& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
str.set_mode(cdr_stream::stream_mode::write, key);
return write(str, instance, props.data());
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool read(T& streamer, ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!read(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!read(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool read(S& str, ::ddkit_intern::TestTopic2& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
str.set_mode(cdr_stream::stream_mode::read, key);
return read(str, instance, props.data());
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool move(T& streamer, const ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!move(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!move(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool move(S& str, const ::ddkit_intern::TestTopic2& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
str.set_mode(cdr_stream::stream_mode::move, key);
return move(str, instance, props.data());
}
template<typename T, std::enable_if_t<std::is_base_of<cdr_stream, T>::value, bool> = true >
bool max(T& streamer, const ::ddkit_intern::TestTopic2& instance, const entity_properties_t *props) {
(void)instance;
member_id_set member_ids;
if (!streamer.start_struct(*props))
return false;
auto prop = streamer.first_entity(props);
while (prop) {
switch (prop->m_id) {
case 0:
if (!streamer.start_member(*prop))
return false;
if (!max(streamer, instance.id()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
case 1:
if (!streamer.start_member(*prop))
return false;
if (!max(streamer, instance.val()))
return false;
if (!streamer.finish_member(*prop, member_ids))
return false;
break;
}
prop = streamer.next_entity(prop);
}
return streamer.finish_struct(*props, member_ids);
}
template<typename S, std::enable_if_t<std::is_base_of<cdr_stream, S>::value, bool> = true >
bool max(S& str, const ::ddkit_intern::TestTopic2& instance, key_mode key) {
const auto &props = get_type_props<::ddkit_intern::TestTopic2>();
str.set_mode(cdr_stream::stream_mode::max, key);
return max(str, instance, props.data());
}
} //namespace cdr
} //namespace core
} //namespace cyclonedds
} //namespace eclipse
} //namespace org
#endif // DDSCXX_TESTTOPIC_HPP_5D6BACE0D1D9ADC0287C638316554B9B
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include <functional>
#include <vector>
#include <string>
#include <iostream>
namespace ddkit {
namespace utils {
namespace callback {
template<class Actor, typename... Args>
class Wrapper;
class Base {
public:
virtual ~Base(){}
template<class Actor, typename... Args>
void tryToInvoke(void (Actor::*func)(Args...), Args&&... args) {
auto cb = dynamic_cast<Wrapper<Actor, Args...>*>(this);
if(cb && cb->isFunction(func)){
cb->invoke(args...);
}
}
};
template<class Actor, typename... Args>
class Wrapper : public Base {
public:
using ActorType = Actor;
using CallbackType = std::function<void(Args...)>;
using ActorFunctionType = void (Actor::*)(Args...);
Wrapper() = delete;
virtual ~Wrapper(){}
Wrapper(ActorFunctionType func, CallbackType cb)
: m_actorFunction(func)
, m_callback(cb)
{
}
bool isFunction(ActorFunctionType func){
return m_actorFunction == func;
}
void invoke(Args... args){
m_callback(args...);
}
private:
friend class Base;
ActorFunctionType m_actorFunction;
CallbackType m_callback;
};
template<class Actor, typename... Args>
Wrapper<Actor, Args...>* Callback(void (Actor::*pm)(Args...), std::function<void(Args...)> cb){
return new Wrapper<Actor, Args...>(pm, cb);
}
template<class Actor, typename... Args, typename Fn>
Wrapper<Actor, Args...>* Callback(void (Actor::*pm)(Args...), const Fn& callback){
return new Wrapper<Actor, Args...>(pm, std::function<void(Args...)>(callback));
}
} // callback
} // utils
namespace callback = ddkit::utils::callback;
} // ddkit
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <exception>
#include <functional>
#include <vector>
namespace ddkit {
namespace utils {
namespace exceptions {
class GlobalHandler {
public:
template<typename Exception> static void registerHandler(std::function<void(Exception&)> handler){
instance().m_registeredHandlers.push_back([handler](std::exception_ptr exceptionPtr){
try {
std::rethrow_exception(exceptionPtr);
} catch (Exception& e) {
handler(e);
} catch (...){
// NO OP
}
});
}
static void registerHandler(std::function<void(std::exception_ptr)> handler){
instance().m_registeredHandlers.push_back(handler);
}
private:
std::terminate_handler m_previousHandler;
std::vector<std::function<void(std::exception_ptr)>> m_registeredHandlers;
GlobalHandler();
void handleException(const std::exception_ptr&);
static GlobalHandler& instance();
static void terminateHandler();
};
} // namespace exceptions
} // namespace utils
} // namespace ddkit
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include <cstddef>
#include <iostream>
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
#endif
//#define DDKIT_ENABLE_LIFETIME_LOGGER
namespace ddkit {
namespace utils {
namespace log {
template <typename Type>
class LifetimeLogger {
public:
LifetimeLogger() {
#ifdef DDKIT_ENABLE_LIFETIME_LOGGER
std::cerr << "Constructor of:\t" << typeName() << " @ " << this << std::endl;
#endif
}
~LifetimeLogger() {
#ifdef DDKIT_ENABLE_LIFETIME_LOGGER
std::cerr << "Destructor of: \t" << typeName() << " @ " << this << std::endl;
#endif
}
private:
std::string typeName() const {
#ifdef __GNUG__
const char* mangled = typeid(Type).name();
int status = 0;
char* name = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
if(status == 0) {
std::string demangledName(name);
delete name;
return demangledName;
}
return mangled;
#else
return typeid(Type).name();
#endif
}
};
} // namespace log
} // namespace utils
} // namespace ddkit
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include <iostream>
#include <sstream>
#include <functional>
#include <fstream>
#include <mutex>
#include "ddkit/utils/Logger.hpp"
namespace ddkit {
namespace utils {
namespace log {
namespace sinks {
// writes all lines to std::ostream after applying ANSI color codes
class OStreamSink : public Sink {
public:
OStreamSink(const base::IConfig& config, std::ostream& stream);
void write(Level level, const std::string& prefix, const std::string& line) override;
private:
std::mutex m_writeMutex;
bool m_doColorize;
std::ostream& m_stream;
static const Registrar<OStreamSink> s_registrarCerr;
static const Registrar<OStreamSink> s_registrarCout;
};
// writes all lines to logfile
class FileSink : public Sink {
public:
FileSink(const base::IConfig& config);
void write(Level level, const std::string& prefix, const std::string& line) override;
private:
void openFile();
void rotateLog();
void incrementFileRecursive(size_t count); // moves m_file<count> to m_file<count+1>
// log rotate settings
bool m_rotateOnStartup;
size_t m_rotateOnFileSize;
size_t m_rotateOnLineCount;
size_t m_rotateKeptFileCount;
size_t m_currentLinesInFile;
std::mutex m_writeMutex;
std::mutex m_logRotateMutex;
std::string m_filename;
std::ofstream m_fh;
static const Registrar<FileSink> s_registrar;
};
} // namespace sinks
} // namespace log
} // namespace utils
} // namespace ddkit
+166
View File
@@ -0,0 +1,166 @@
#pragma once
#include "ddkit/utils/container.hpp"
#include "ddkit/utils/system.hpp"
#include <sstream>
#include <string>
#include <queue>
#include <memory>
#include <functional>
// platforms either define __FUNCSIG__ (MSVC), or __PRETTY_FUNCTION__ (gcc, clang)
#ifdef _WIN32
#define DDKIT_LOG_FUNCSIG __FUNCSIG__
#else
#define DDKIT_LOG_FUNCSIG __PRETTY_FUNCTION__
#endif
#define DDKIT_LOG_LOCATION (ddkit::utils::system::filename(std::string(__FILE__)) + ":" + __LINE__)
#define DDKIT_LOG_LOCATION_STREAM ddkit::utils::system::filename(std::string(__FILE__)) << ":" << __LINE__ << ":" << DDKIT_LOG_FUNCSIG
#define DDKIT_LOG_VAR_VALUE(val) #val << "==" << (val)
// Only for trace, there would be anyway a macro needed for line
#define DDKIT_LOG_TRACE ddkit::utils::log::trace() << "(" << DDKIT_LOG_LOCATION_STREAM << ") "
namespace ddkit {
namespace base {
class IConfig;
class Config;
}
namespace utils {
namespace log {
enum class Level {
None = 0x0, // 0b00000000
Fatal = 0x1, // 0b00000001
Error = 0x3, // 0b00000011
Warn = 0x7, // 0b00000111
Info = 0xF, // 0b00001111
// ?? = 0x1F, // 0b00011111 RESERVED
Debug = 0x3F, // 0b00111111
// ?? = 0x7F, // 0b01111111 RESERVED
Trace = 0xFF, // 0b11111111
};
class Sink;
typedef std::shared_ptr<Sink> SinkPtr;
class Logger {
using SinkFactoryFunction = std::function<SinkPtr(const base::IConfig&)>;
public:
static void loadConfig(const base::Config&);
static void registerSinkType(const std::string& id, const SinkFactoryFunction& factory);
static void installSink(const std::string& id, const base::IConfig&);
static void installSink(SinkPtr);
static void write(Level, const std::string&);
static void uninstallAllSinks();
static Level getHighestUsedLevel();
private:
Logger();
Logger(const Logger&) = delete;
static Logger& instance();
static std::string getPrefix(Level);
// shared_ptr/SinkPtr is used to circumvent the issue of having a collection of pure virtual class
std::vector<SinkPtr> m_sinks;
std::map<std::string, SinkFactoryFunction> m_sinkTypes;
// stored for performance reasons, aids in aborting early in LineBuilder if the log level isnt used
Level mHighestLevel;
};
class Sink {
public:
template<class Type> class Registrar;
Sink(const base::IConfig&);
virtual ~Sink(){}
virtual void write(Level level, const std::string& prefix, const std::string& line) = 0;
void setLevel(Level);
void setLevel(const std::string&);
Level getLevel() const;
private:
Sink() = delete;
protected:
Level m_level;
};
template<class Type> class Sink::Registrar {
public:
Registrar() = delete;
// Registrar<FileSink>("file")
Registrar(const std::string& id){
Logger::registerSinkType(id, [](const base::IConfig& config){
return std::make_shared<Type>(config);
});
}
// Registrar<OStreamSink>("cerr", std::cerr)
template<class Param> Registrar(const std::string& id, Param& param){
auto pRef = std::ref(param);
Logger::registerSinkType(id, [pRef](const base::IConfig& config){
return std::make_shared<Type>(config, pRef.get());
});
}
};
/// @brief Stores a number of strings and writes them to log on destruction
class LineBuilder {
public:
LineBuilder(Level);
LineBuilder() = delete;
LineBuilder(const LineBuilder&) = delete;
LineBuilder(LineBuilder&&);
~LineBuilder();
LineBuilder& operator<<(const std::string&);
LineBuilder& operator<<(bool);
template<typename T> LineBuilder& operator<<(const T& value){
if(Logger::getHighestUsedLevel() < m_level) return *this; // early abort for performance gains
m_line << value << " ";
return *this;
}
template<typename T> LineBuilder& operator<<(const std::vector<T>& vec){
if(Logger::getHighestUsedLevel() < m_level) return *this; // early abort for performance gains
m_line << "[";
for(auto it = vec.begin(); it != vec.end(); it++){
*this << *it;
if(vec.end() - it != 1){ // all except for the last element
m_line << ", ";
}
}
*this << "] ";
return *this;
}
private:
Level m_level;
std::ostringstream m_line;
};
LineBuilder fatal();
LineBuilder error();
LineBuilder warn();
LineBuilder info();
LineBuilder debug();
LineBuilder trace();
} // namespace log
} // namespace utils
namespace log = ddkit::utils::log;
} // namespace ddkit
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "ddkit/utils/Logger.hpp"
#include <signal.h>
#define DDKIT_THROW_ON_FALSE(cond) \
if (!(cond)) { \
/*raise(SIGTRAP); */ \
std::string msg = std::string("Assertion \"" #cond "\" failed in ") + __FILE__ + ":" + std::to_string(__LINE__); \
ddkit::log::fatal() << msg; \
throw std::logic_error(msg); \
}
#define DDKIT_THROW_ON_FALSE_INFO(cond, info) \
if (!(cond)) { \
/*raise(SIGTRAP);*/ \
std::string msg = std::string("Assertion \"" #cond "\" failed in ") + __FILE__ + ":" + std::to_string(__LINE__); \
ddkit::log::fatal() << msg << " :" << std::string(info); \
throw std::logic_error(msg + " :" + std::string(info)); \
}
+116
View File
@@ -0,0 +1,116 @@
#pragma once
#include <algorithm>
#include <set>
#include <vector>
#include <map>
#include <ostream>
#include <memory>
namespace ddkit {
namespace utils {
namespace container {
template <typename Container, typename Value>
bool contains(Container container, Value value) {
return std::find(container.begin(), container.end(), value) != container.end();
}
template <typename T>
std::vector<T> set2vector(std::set<T> p_set) {
std::vector<T> r_vec;
std::copy(p_set.begin(), p_set.end(), std::back_inserter(r_vec));
return r_vec;
}
template <typename T>
std::set<T> vector2set(std::vector<T> p_vec) {
std::set<T> r_set;
std::copy(p_vec.begin(), p_vec.end(), std::inserter(r_set, r_set.begin()));
return r_set;
}
template <typename T>
typename std::set<T> set_difference(typename std::set<T> const& minuend, typename std::set<T> const& subtrahend) {
std::set<T> diff;
std::set_difference(
minuend.begin(),
minuend.end(),
subtrahend.begin(),
subtrahend.end(),
std::inserter(diff, diff.end()));
return diff;
}
template <typename T>
typename std::vector<T> vector_difference(typename std::vector<T> const& minuend, typename std::vector<T> const& subtrahend) {
std::vector<T> diff;
std::copy_if(minuend.begin(), minuend.end(), std::back_inserter(diff), [subtrahend](const T& element) {
return !contains(subtrahend, element);
});
return diff;
}
inline std::string quotify(const std::string& input) { return "\"" + input+ "\""; }
template<typename T> T quotify(T t) { return t; }
template <typename T>
std::ostream& operator<<(std::ostream& s, std::vector<T> rhs) {
bool isFirst = true;
s << "[";
for (auto const& i : rhs) {
if (isFirst) isFirst = false;
else s << ", ";
s << quotify<T>(i);
}
s << "]";
return s;
}
template <typename T, typename U>
std::ostream& operator<<(std::ostream& s, std::pair<T, U> rhs) {
return s << rhs.first << ":" << quotify<U>(rhs.second);
}
template <typename T, typename U>
std::ostream& operator<<(std::ostream& s, std::map<T, U> rhs) {
bool isFirst = true;
s << "{";
for (auto const& i : rhs) {
if (isFirst) isFirst = false;
else s << ", ";
s << i;
}
s << "}";
return s;
}
template <typename T>
std::ostream& operator<<(std::ostream& s, std::set<T> rhs) {
bool isFirst = true;
s << "[";
for (auto const& i : rhs) {
if (isFirst) isFirst = false;
else s << ", ";
s << quotify<T>(i);
}
s << "]";
return s;
}
template <typename T>
std::ostream& operator<<(std::ostream& s, std::weak_ptr<T> rhs) {
if(rhs.expired()){
s << "<expired>";
} else {
s << rhs.lock();
}
return s;
}
} // container
} // utils
using ddkit::utils::container::operator<<;
} // ddkit
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include <vector>
namespace ddkit {
namespace utils {
namespace types {
template <typename T>
class Optional {
private:
std::vector<T> &vec;
public:
Optional(std::vector<T> &val) : vec(val) {}
Optional() = delete;
T& value() {
if(vec.size()) {
return vec[0];
} else {
throw std::out_of_range( "optional is empty" );
}
}
T value_or(T defVal) {
return vec.size() ? vec[0] : (defVal);
}
void reset() {
if (vec.size()) {
vec.clear();
}
}
void set(const T &val) {
if (vec.size()) {
vec[0] = val;
} else {
vec.push_back(val);
}
}
bool has_value() const {
return vec.size() ? true : false;
}
std::vector<T> &operator*() {
return vec[0];
}
std::vector<T> *operator->() {
return vec[0];
}
Optional operator=(const T &val) {
set(val);
return *this;
}
operator bool() const {
return has_value();
}
};
}
}
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <string>
#include <vector>
namespace ddkit {
namespace utils {
namespace string {
bool beginsWith(const std::string& text, const std::string& prefix);
bool endsWith(const std::string& text, const std::string& suffix);
bool contains(const std::string& container, const std::string& containee);
void removePrefix(std::string& line, const std::string& prefix);
void removePrefixIf(std::string& line, const std::string& prefix);
void removeSuffix(std::string& line, const std::string& suffix);
void removeSuffixIf(std::string& line, const std::string& suffix);
std::string trimLeft(const std::string& text);
std::string trimRight(const std::string& text);
std::string trim(const std::string& text);
std::string toLower(const std::string& text);
std::string toUpper(const std::string& text);
std::string toFirstUpper(const std::string& text);
std::string replace(std::string text, const std::string& from, const std::string& to);
std::vector<std::string> split(const std::string& text, char delim);
std::string join(const std::vector<std::string>&, const std::string& delimiter);
bool isInt(const std::string& text);
int toInt(const std::string& text);
bool isInt64(const std::string& text);
int64_t toInt64(const std::string& text);
} // namespace string
} // namespace utils
} // namespace ddkit
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <vector>
namespace ddkit {
namespace utils {
namespace system {
void sleep(int secs); // sleep seconds (instead of unix-sleep)
void msSleep(int milliSecs); // sleep milliseconds (instead of unix-sleep)
std::string getEnv(const std::string& var);
std::string getEnv(const std::string& var, const std::string& defaultVal);
bool setEnv(const std::string& name, const std::string& value);
std::string dirname(std::string text); // "path/to/file.cpp" -> "path/to/"
std::string filename(std::string text); // "path/to/file.cpp" -> "file" / "path/to/file.hpp" -> "file.hpp"
std::string filenameBase(std::string text); // "path/to/file.xyz" -> "file.cpp" -> "file"
int getProcessId();
std::string getProcessName(); // "some_name"
std::string getProcessNameWithPath(); // "/user/local/bin/some_name.exe"
std::string getHostname();
std::string threadIdCurrent();
void blockSignals(); // blocks SIGINT/SIGHUP/SIGKILL for current thread. does nothing on windows
void waitForSignal(); // waits for SIGINT/SIGHUP/SIGKILL, or windows ctrl-c
bool isFileReadable(const std::string& filename); // does a file exist and does open succeed?
bool renameFile(const std::string& oldName, const std::string& newName);
bool deleteFile(const std::string& name);
void setNativeThreadName(const std::string& name);
std::string getNativeThreadName();
} // namespace system
} // namespace utils
} // namespace ddkit
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <chrono>
namespace ddkit {
namespace utils {
namespace time {
int64_t getCurrentUnixTimestamp();
}
}
}