Program Listing for File channel.hpp
↰ Return to documentation for file (/tmp/ws/src/data_tamer/data_tamer_cpp/include/data_tamer/channel.hpp
)
#pragma once
#include "data_tamer/values.hpp"
#include "data_tamer/data_sink.hpp"
#include "data_tamer/details/mutex.hpp"
#include "data_tamer/details/locked_reference.hpp"
#include <chrono>
#include <memory>
namespace DataTamer
{
// Utility
inline std::chrono::nanoseconds NsecSinceEpoch()
{
auto since_epoch = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::nanoseconds>(since_epoch);
}
class DataSinkBase;
class LogChannel;
class ChannelsRegistry;
template <typename T>
class LoggedValue
{
protected:
LoggedValue(const std::shared_ptr<LogChannel>& channel, const std::string& name,
T initial_value);
friend LogChannel;
public:
LoggedValue() {}
~LoggedValue();
LoggedValue(LoggedValue const& other) = delete;
LoggedValue& operator=(LoggedValue const& other) = delete;
LoggedValue(LoggedValue&& other) = default;
LoggedValue& operator=(LoggedValue&& other) = default;
void set(const T& value, bool auto_enable = true);
[[nodiscard]] T get();
[[nodiscard]] LockedRef<T, Mutex> getLockedReference();
void setEnabled(bool enabled);
[[nodiscard]] bool isEnabled() const { return enabled_; }
private:
std::weak_ptr<LogChannel> channel_;
T value_ = {};
RegistrationID id_;
bool enabled_ = true;
};
//---------------------------------------------------------
class LogChannel : public std::enable_shared_from_this<LogChannel>
{
protected:
// We make this private because the object must be wrapped
// inside a std::shared_ptr.
// This allows us to use std::weak_ptr in LoggedValue
LogChannel(std::string name);
public:
static std::shared_ptr<LogChannel> create(std::string name);
~LogChannel();
LogChannel(const LogChannel&) = delete;
LogChannel& operator=(const LogChannel&) = delete;
LogChannel(LogChannel&&) = delete;
LogChannel& operator=(LogChannel&&) = delete;
template <typename T>
RegistrationID registerValue(const std::string& name, const T* value);
template <template <class, class> class Container, class T, class... TArgs>
RegistrationID registerValue(const std::string& name,
const Container<T, TArgs...>* value);
template <typename T, size_t N>
RegistrationID registerValue(const std::string& name, const std::array<T, N>* value);
template <typename T>
RegistrationID registerCustomValue(const std::string& name, const T* value,
CustomSerializer::Ptr type_info);
template <typename T = double>
[[nodiscard]] std::shared_ptr<LoggedValue<T>> createLoggedValue(std::string const& name,
T initial_value = T{});
[[nodiscard]] const std::string& channelName() const;
void setEnabled(const RegistrationID& id, bool enable);
void unregister(const RegistrationID& id);
void addDataSink(std::shared_ptr<DataSinkBase> sink);
bool takeSnapshot(std::chrono::nanoseconds timestamp = NsecSinceEpoch());
[[nodiscard]] const ActiveMask& getActiveFlags();
[[nodiscard]] Schema getSchema() const;
Mutex& writeMutex();
private:
struct Pimpl;
std::unique_ptr<Pimpl> _p;
TypesRegistry _type_registry;
template <typename T>
void updateTypeRegistry();
template <typename T>
void updateTypeRegistryImpl(FieldsVector& fields, const char* name);
void addCustomType(const std::string& custom_type_name, const FieldsVector& fields);
[[nodiscard]] RegistrationID registerValueImpl(const std::string& name,
ValuePtr&& value_ptr,
CustomSerializer::Ptr type_info);
};
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
template <typename T>
void LogChannel::updateTypeRegistryImpl(FieldsVector& fields, const char* field_name)
{
using SerializeMe::container_info;
TypeField field;
field.field_name = field_name;
field.type = GetBasicType<T>();
if constexpr (GetBasicType<T>() == BasicType::OTHER)
{
field.type_name = TypeDefinition<T>().typeName();
if constexpr (container_info<T>::is_container)
{
field.is_vector = true;
field.array_size = container_info<T>::size;
using Type = typename container_info<T>::value_type;
updateTypeRegistry<Type>();
}
else
{
updateTypeRegistry<T>();
}
}
fields.push_back(field);
}
template <typename T>
inline void LogChannel::updateTypeRegistry()
{
FieldsVector fields;
if constexpr (!IsNumericType<T>())
{
const auto& type_name = DataTamer::TypeDefinition<T>().typeName();
auto added_serializer = _type_registry.addType<T>(type_name, true);
if (added_serializer)
{
if constexpr (has_typedef_with_object<T>())
{
auto func = [this, &fields](const char* field_name, const auto* member) {
using MemberType =
typename std::remove_cv_t<std::remove_reference_t<decltype(*member)>>;
updateTypeRegistryImpl<MemberType>(fields, field_name);
};
TypeDefinition<T>().typeDef({}, func);
}
else
{
auto func = [this, &fields](const char* field_name, const auto& member) {
using MemberType = decltype(getPointerType(member));
this->updateTypeRegistryImpl<MemberType>(fields, field_name);
};
TypeDefinition<T>().typeDef(func);
}
addCustomType(type_name, fields);
}
}
}
template <typename T>
inline RegistrationID LogChannel::registerValue(const std::string& name,
const T* value_ptr)
{
if constexpr (IsNumericType<T>())
{
return registerValueImpl(name, ValuePtr(value_ptr), {});
}
else
{
updateTypeRegistry<T>();
auto def = _type_registry.getSerializer<T>();
return registerValueImpl(name, ValuePtr(value_ptr, def), def);
}
}
template <typename T>
inline RegistrationID LogChannel::registerCustomValue(const std::string& name,
const T* value_ptr,
CustomSerializer::Ptr serializer)
{
static_assert(!IsNumericType<T>(), "This method should be used only for custom types");
return registerValueImpl(name, ValuePtr(value_ptr, serializer), serializer);
}
template <template <class, class> class Container, class T, class... TArgs>
inline RegistrationID LogChannel::registerValue(const std::string& prefix,
const Container<T, TArgs...>* vect)
{
if constexpr (IsNumericType<T>())
{
return registerValueImpl(prefix, ValuePtr(vect), {});
}
else
{
updateTypeRegistry<T>();
auto def = _type_registry.getSerializer<T>();
return registerValueImpl(prefix, ValuePtr(vect), def);
}
}
template <typename T, size_t N>
inline RegistrationID LogChannel::registerValue(const std::string& prefix,
const std::array<T, N>* vect)
{
if constexpr (IsNumericType<T>())
{
return registerValueImpl(prefix, ValuePtr(vect), {});
}
else
{
updateTypeRegistry<T>();
auto def = _type_registry.getSerializer<T>();
return registerValueImpl(prefix, ValuePtr(vect, def), def);
}
}
template <typename T>
inline std::shared_ptr<LoggedValue<T>>
LogChannel::createLoggedValue(std::string const& name, T initial_value)
{
auto val = new LoggedValue<T>(shared_from_this(), name, initial_value);
return std::shared_ptr<LoggedValue<T>>(val);
}
template <typename T>
inline LoggedValue<T>::LoggedValue(const std::shared_ptr<LogChannel>& channel,
const std::string& name, T initial_value) :
channel_(channel), value_(initial_value), id_(channel->registerValue(name, &value_))
{}
template <typename T>
inline LoggedValue<T>::~LoggedValue()
{
if (auto channel = channel_.lock())
{
channel->unregister(id_);
}
}
template <typename T>
inline void LoggedValue<T>::setEnabled(bool enabled)
{
if (auto channel = channel_.lock())
{
channel->setEnabled(id_, enabled);
}
enabled_ = enabled;
}
template <typename T>
inline void LoggedValue<T>::set(const T& val, bool auto_enable)
{
if (auto channel = channel_.lock())
{
value_ = val;
if (!enabled_ && auto_enable)
{
channel->setEnabled(id_, true);
enabled_ = true;
}
}
else
{
value_ = val;
enabled_ |= auto_enable;
}
}
template <typename T>
inline T LoggedValue<T>::get()
{
if (auto channel = channel_.lock())
{
std::lock_guard const lock(channel->writeMutex());
return value_;
}
return value_;
}
template <typename T>
inline LockedRef<T, Mutex> LoggedValue<T>::getLockedReference()
{
Mutex* mutex_ptr = nullptr;
if (auto chan = channel_.lock())
{
mutex_ptr = &chan->writeMutex();
}
return LockedRef<T, Mutex>(&value_, mutex_ptr);
}
} // namespace DataTamer