Page MenuHomePhorge

No OneTemporary

Size
142 KB
Referenced Files
None
Subscribers
None
diff --git a/include/rosa/agent/History.hpp b/include/rosa/agent/History.hpp
index 93e37ef..61c5fe8 100644
--- a/include/rosa/agent/History.hpp
+++ b/include/rosa/agent/History.hpp
@@ -1,586 +1,586 @@
//===-- rosa/agent/History.hpp ----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/History.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Definition of *history* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_HISTORY_HPP
#define ROSA_AGENT_HISTORY_HPP
#include "rosa/agent/Functionality.h"
#include "rosa/config/config.h"
#include "rosa/support/debug.hpp"
#include "rosa/support/type_helper.hpp"
#include <algorithm>
#include <array>
#include <limits>
#include <vector>
namespace rosa {
namespace agent {
// @benedikt: todo: assert in history, which checks if push_back worked
/// Retention policies defining what a \c rosa::agent::History instance should
/// do when the number of recorded entries reached its capacity.
enum class HistoryPolicy {
SRWF, ///< Stop Recording When Full -- no new entry is recorded when full
FIFO, ///< First In First Out -- overwrite the earliest entry with a new one
LIFO ///< Last In First Out -- overwrite the latest entry with a new one
};
template <typename T, HistoryPolicy P> class History : public Functionality {
public:
- History(void) noexcept {}
+ History(void) noexcept = default;
/// Destroys \p this object.
virtual ~History(void) = default;
/// Tells the retention policy applied to \p this object.
///
/// \return \c rosa::agent::History::P
static constexpr HistoryPolicy policy(void) noexcept { return P; }
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return The max number of entries that may be recorded
virtual size_t maxLength(void) const noexcept = 0;
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
/// \endcode
virtual size_t numberOfEntries(void) const noexcept = 0;
/// Tells if \p this object has not recorded anything yet.
///
/// \return if \p this object has no entries recorded
bool empty(void) const noexcept { return numberOfEntries() == 0; }
/// Tells if the history reached it's maximum length
///
/// \return if the history reached it's maximum length.
bool full(void) const noexcept { return numberOfEntries() == maxLength(); }
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
virtual const T &entry(const size_t I = 0) const noexcept = 0;
/// Removes all entries recorded in \p this object.
virtual void clear() noexcept = 0;
private:
/// Pushes a new entry into the history.
///
/// \note The earliest entry gets overwritten if the history is full.
///
/// \param V value to push into the history
virtual void pushBack(const T &V) noexcept = 0;
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
virtual void replaceFront(const T &V) noexcept = 0;
public:
/// Adds a new entry to \p this object and tells if the operation was
/// successful.
///
/// \note Success of the operation depends on the actual policy.
///
/// \param V value to store
///
/// \return if \p V was successfully stored
bool addEntry(const T &V) noexcept {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::LIFO:
if (full()) {
replaceFront(V);
return true;
}
case HistoryPolicy::SRWF:
if (full()) {
return false;
}
// \note Fall through to FIFO which unconditionally pushes the new entry.
case HistoryPolicy::FIFO:
// FIFO and SRWF not full.
pushBack(V);
return true;
}
}
/// Tells the trend set by the entries recorded by \p this object.
///
/// The number of steps to go back when calculating the trend is defined as
/// argument to the function.
///
/// \note The number of steps that can be made is limited by the number of
/// entries recorded by \p this object.
///
/// \note The function is made a template only to be able to use
/// \c std::enable_if.
///
/// \tparam X always use the default!
///
/// \param D number of steps to go back in *history*
///
/// \return trend set by analyzed entries
///
/// \pre Statically, \p this object stores signed arithmetic values:\code
/// std::is_arithmetic<T>::value && std::is_signed<T>::value
/// \endcode Dynamically, \p D is a valid number of steps to take:\code
/// 0 <= D && D < lengthOfHistory()
/// \endcode
template <typename X = T>
typename std::enable_if<
std::is_arithmetic<X>::value && std::is_signed<X>::value, X>::type
trend(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < maxLength()); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No entries for computing trend.
return {}; // Zero element of \p T
} else {
// Here at least two entries.
// \c S is the number of steps that can be done.
const size_t S = std::min(numberOfEntries() - 1, D);
size_t I = S;
// Compute trend with linear regression.
size_t SumIndices = 0;
T SumEntries = {};
T SumSquareEntries = {};
T SumProduct = {};
while (I > 0) {
// \note Indexing for the regression starts in the past.
const size_t Index = S - I;
const T Entry = entry(--I);
SumIndices += Index;
SumEntries += Entry;
SumSquareEntries += Entry * Entry;
SumProduct += Entry * Index;
}
return (SumProduct * S - SumEntries * SumIndices) /
(SumSquareEntries * S - SumEntries * SumEntries);
}
}
/// Tells the average absolute difference between consecutive entries recorded
/// by \p this object
/// The number of steps to go back when calculating the average is defined as
/// argument to the function.
///
/// \note The number of steps that can be made is limited by the number of
/// entries recorded by \p this object.
///
/// \note The function is made a template only to be able to use
/// \c std::enable_if.
///
/// \tparam X always use the default!
///
/// \param D number of steps to go back in *history*
///
/// \pre Statically, \p this object stores arithmetic values:\code
/// std::is_arithmetic<T>::value
/// \endcode Dynamically, \p D is a valid number of steps to take:\code
/// 0 <= D && D < lengthOfHistory()
/// \endcode
template <typename X = T>
typename std::enable_if<std::is_arithmetic<X>::value, size_t>::type
averageAbsDiff(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < maxLength()); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No difference to average.
return {}; // Zero element of \p T
} else {
// Here at least two entries.
// \c S is the number of steps that can be done.
const size_t S = std::min(numberOfEntries() - 1, D);
// Sum up differences as non-negative values only, hence using an
// unsigned variable for that.
size_t Diffs = {}; // Init to zero.
// Count down entry indices and sum up all the absolute differences.
size_t I = S;
T Last = entry(I);
while (I > 0) {
T Next = entry(--I);
Diffs += Last < Next ? Next - Last : Last - Next;
Last = Next;
}
// Return the average of the summed differences.
return Diffs / S;
}
}
/// Tells the average of all entries recorded by \p this object
///
/// \tparam R type of the result
template <typename R> R average() const noexcept {
R Average = 0;
for (size_t I = 0; I < numberOfEntries(); I++) {
Average += entry(I);
}
Average /= numberOfEntries();
return Average;
}
};
/// Implements *history* by recording and storing values.
/// The length of the underlying std::array is static and must be set at
/// compile-time
///
/// \note Not thread-safe implementation, which should not be a problem as any
/// instance of \c rosa::agent::Functionality is an internal component of a
/// \c rosa::Agent, which is the basic unit of concurrency.
///
/// \tparam T type of values to store
/// \tparam N number of values to store at most
/// \tparam P retention policy to follow when capacity is reached
///
/// \invariant The size of the underlying \c std::array is `N + 1`:\code
/// max_size() == N + 1 && N == max_size() - 1
/// \endcode
template <typename T, size_t N, HistoryPolicy P>
class StaticLengthHistory : public History<T, P>, private std::array<T, N + 1> {
// Bring into scope inherited functions that are used.
using std::array<T, N + 1>::max_size;
using std::array<T, N + 1>::operator[];
/// The index of the first data element in the circular buffer.
size_t Data;
/// The index of the first empty slot in the circular buffer.
size_t Space;
public:
using History<T, P>::policy;
using History<T, P>::empty;
using History<T, P>::full;
using History<T, P>::addEntry;
using History<T, P>::trend;
using History<T, P>::averageAbsDiff;
/// Creates an instances by initializing the indices for the circular buffer.
StaticLengthHistory(void) noexcept : Data(0), Space(0) {}
/// Destroys \p this object.
~StaticLengthHistory(void) override = default;
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return \c rosa::agent::History::N
size_t maxLength(void) const noexcept override { return N; }
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
/// \endcode
size_t numberOfEntries(void) const noexcept override {
return Data <= Space ? Space - Data : max_size() - Data + Space;
}
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
const T &entry(const size_t I = 0) const noexcept override {
ASSERT(0 <= I && I < numberOfEntries()); // Boundary check.
// Position counted back from the last recorded entry.
typename std::make_signed<const size_t>::type Pos = Space - (1 + I);
// Actual index wrapped around to the end of the buffer if negative.
return (*this)[Pos >= 0 ? Pos : max_size() + Pos];
}
/// Removes all entries recorded in \p this object.
void clear() noexcept override {
Data = 0;
Space = 0;
}
private:
/// Pushes a new entry into the circular buffer.
///
/// \note The earliest entry gets overwritten if the buffer is full.
///
/// \param V value to push into the buffer
void pushBack(const T &V) noexcept override {
// Store value to the first empty slot and step Space index.
(*this)[Space] = V;
Space = (Space + 1) % max_size();
if (Data == Space) {
// Buffer was full, step Data index.
Data = (Data + 1) % max_size();
}
}
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
void replaceFront(const T &V) noexcept override {
(*this)[(Space - 1) % max_size()] = V;
}
};
/// Adds a new entry to a \c rosa::agent::History instance.
///
/// \note The result of \c rosa::agent::History::addEntry is ignored.
///
/// \tparam T type of values stored in \p H
/// \tparam N number of values \p H is able to store
/// \tparam P retention policy followed by \p H when capacity is reached
///
/// \param H to add a new entry to
/// \param V value to add to \p H
///
/// \return \p H after adding \p V to it
template <typename T, size_t N, HistoryPolicy P>
StaticLengthHistory<T, N, P> &operator<<(StaticLengthHistory<T, N, P> &H,
const T &V) noexcept {
H.addEntry(V);
return H;
}
/// Implements *DynamicLengthHistory* by recording and storing values.
///
/// \note Not thread-safe implementation, which should not be a problem as any
/// instance of \c rosa::agent::Functionality is an internal component of a
/// \c rosa::Agent, which is the basic unit of concurrency.
///
/// \tparam T type of values to store
/// \tparam P retention policy to follow when capacity is reached
template <typename T, HistoryPolicy P>
class DynamicLengthHistory : public History<T, P>, private std::vector<T> {
private:
// Bring into scope inherited functions that are used.
using std::vector<T>::size;
using std::vector<T>::resize;
using std::vector<T>::push_back;
using std::vector<T>::pop_back;
using std::vector<T>::max_size;
/// The current length of the DynamicLengthHistory.
size_t Length;
public:
// Bring into scope inherited functions that are used.
using std::vector<T>::erase;
using std::vector<T>::begin;
using std::vector<T>::end;
using std::vector<T>::rbegin;
using std::vector<T>::rend;
using std::vector<T>::operator[];
// Bring into scope inherited functions that are used.
using History<T, P>::policy;
using History<T, P>::empty;
using History<T, P>::full;
using History<T, P>::addEntry;
using History<T, P>::trend;
using History<T, P>::averageAbsDiff;
/// Creates an instances by setting an initial length
DynamicLengthHistory(size_t Length) noexcept : Length(Length) {}
/// Destroys \p this object.
~DynamicLengthHistory(void) override = default;
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return \c rosa::agent::DynamicLengthHistory::N
size_t maxLength(void) const noexcept override { return Length; }
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <=
/// lengthOfHistory() \endcode
size_t numberOfEntries(void) const noexcept override { return size(); }
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
const T &entry(const size_t I = 0) const noexcept override {
ASSERT(0 <= I && I < numberOfEntries()); // Boundary check.
return this->operator[](size() - I - 1);
}
/// Removes all entries recorded in \p this object.
void clear() noexcept override { erase(begin(), end()); }
/// Sort all entries in ascending order.
void sortAscending(void) noexcept { std::sort(begin(), end()); }
/// Sort all entries in descending order.
void sortDescending(void) noexcept { std::sort(rbegin(), rend()); }
/// Delets one element of the history.
///
/// \param V the element which shall be deleted.
void deleteEntry(T &V) {
auto it = std::find(begin(), end(), V);
if (it != end()) {
erase(it);
}
}
/// Gives back the lowest entry of the history.
///
/// \return the lowest entry. In case of an empty history, the maximum value
/// of the chosen data type is returned.
T lowestEntry() {
auto it = std::min_element(begin(), end());
if (it == end()) {
return std::numeric_limits<T>::max();
} else {
return *it;
}
}
/// Gives back the highest entry of the history.
///
/// \return the highest entry. In case of an empty history, the minimum value
/// of the chosen data type is returned.
T highestEntry() {
auto it = std::max_element(begin(), end());
if (it == end()) {
return std::numeric_limits<T>::min();
} else {
return *it;
}
}
private:
/// Pushes a new entry into the circular buffer.
///
/// \note The earliest entry gets overwritten if the buffer is full.
///
/// \param V value to push into the buffer
void pushBack(const T &V) noexcept override {
if (full()) {
erase(begin());
}
push_back(V);
}
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
void replaceFront(const T &V) noexcept override {
(void)pop_back();
push_back(V);
}
public:
/// Resizes the History length. If the new length is smaller than the number
/// of currently stored values, values are deleted according to the
/// HistoryPolicy.
///
/// @param NewLength The new Length of the History.
void setLength(size_t NewLength) noexcept {
Length = NewLength;
if (NewLength < numberOfEntries()) {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::LIFO:
case HistoryPolicy::SRWF:
// Delete last numberOfEntries() - NewLength items from the back
erase(begin() + NewLength, end());
break;
case HistoryPolicy::FIFO:
// Delete last numberOfEntries() - NewLength items from the front
erase(begin(), begin() + (numberOfEntries() - NewLength));
break;
}
}
this->resize(Length);
}
};
/// Adds a new entry to a \c rosa::agent::DynamicLengthHistory instance.
///
/// \note The result of \c rosa::agent::DynamicLengthHistory::addEntry is
/// ignored.
///
/// \tparam T type of values stored in \p H
/// \tparam P retention policy followed by \p H when capacity is reached
///
/// \param H to add a new entry to
/// \param V value to add to \p H
///
/// \return \p H after adding \p V to it
template <typename T, HistoryPolicy P>
DynamicLengthHistory<T, P> &operator<<(DynamicLengthHistory<T, P> &H,
const T &V) noexcept {
H.addEntry(V);
return H;
}
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_HISTORY_HPP
diff --git a/include/rosa/agent/ReliabilityConfidenceCombinator.h b/include/rosa/agent/ReliabilityConfidenceCombinator.h
index b1387f8..734840a 100644
--- a/include/rosa/agent/ReliabilityConfidenceCombinator.h
+++ b/include/rosa/agent/ReliabilityConfidenceCombinator.h
@@ -1,773 +1,773 @@
//===-- rosa/agent/ReliabilityConfidenceCombinator.h ------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/ReliabilityConfidenceCombinator.h
///
/// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *ReliabilityConfidenceCombinator* *functionality*.
///
/// \note based on Maximilian Goetzinger (maxgot@utu.fi) code in
/// CAM_Dirty_include SA-EWS2_Version... inside Agent.cpp
///
/// \note By defining and setting Reliability_trace_level it is possible to
/// change the level to which it should be traced. \note All classes throw
/// runtime errors if not all things are set
///
/// \note should the Reliability be capped?
///
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_ReliabilityConfidenceCombinator_H
#define ROSA_AGENT_ReliabilityConfidenceCombinator_H
#include "rosa/core/forward_declarations.h" // needed for id_t
#include "rosa/support/log.h"
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/Functionality.h"
#include "rosa/agent/RangeConfidence.hpp"
#include <algorithm>
#include <functional>
#include <type_traits>
#include <vector>
/// 0 everything
/// 1 vectors
/// 2 outputs
#define trace_everything 0
#define trace_vectors 1
#define trace_outputs 2
#ifndef Reliability_trace_level
#define Reliability_trace_level 0
#endif
#define trace_end "\n\n\n"
namespace rosa {
namespace agent {
/// This is a struct with a few methods that make Likeliness Combinator
/// more readable \tparam IdentifierType The Data-type of the Identifiers
/// \tparam LikelinessType The Data-type of the Likeliness \note this
/// should/will be changed into a std::pair because it isn't needed anymore
template <typename IdentifierType, typename LikelinessType> struct Symbol {
/// making both Template Arguments readable to make a few things easier
using _IdentifierType = IdentifierType;
/// making both Template Arguments readable to make a few things easier
using _LikelinessType = LikelinessType;
/// The actual place where the data is stored
IdentifierType Identifier;
/// The actual place where the data is stored
LikelinessType Likeliness;
Symbol(IdentifierType _Identifier, LikelinessType _Likeliness)
: Identifier(_Identifier), Likeliness(_Likeliness) {}
- Symbol() {}
+ Symbol() = default;
/// Pushes the Data in a Human readable form
/// \param out The stream where it is written to
/// \param c The struct itself
friend std::ostream &operator<<(std::ostream &out, const Symbol &c) {
out << "Identifier: " << c.Identifier << "\t Likeliness: " << c.Likeliness
<< " ";
return out;
}
/// needed or it throws an clang diagnosic error
using map =
std::map<IdentifierType, LikelinessType>; // needed or it throws an
// clang diagnosic error
/// Filles the vector with the data inside the map
/// \param me The vector to be filled
/// \param data The data wich is to be pushed into the vector
friend std::vector<Symbol> &operator<<(std::vector<Symbol> &me, map &&data) {
for (auto tmp : data) {
me.push_back(Symbol(tmp.first, tmp.second));
#if Reliability_trace_level <= trace_everything
LOG_TRACE_STREAM << "\n" << Symbol(tmp.first, tmp.second) << trace_end;
#endif
}
return me;
}
/// This is to push the data inside a vector in a human readable way into the
/// ostream \param out The ostream \param c The vector which is read
friend std::ostream &operator<<(std::ostream &out,
const std::vector<Symbol> &c) {
std::size_t index = 0;
for (Symbol data : c) {
out << index << " : " << data << "\n";
index++;
}
return out;
}
};
/// This is the combinator for Reliability and confidences it takes the
/// Value, its "History" and feedback from \c
/// CrossCombinator to calculate different Reliabilities.
/// \tparam ValueType Data-type of the Value ( Typically
/// double or float) \tparam IdentifierType Data-type of the Identifier (
/// Typically long or int)
/// \tparam ReliabilityType Data-type of the Reliability (
/// Typically double or float)
///
/// \note more information about how it calculates
/// the Reliabilities it should be considered feedback is a sort of Confidence
/// \verbatim
///----------------------------------------------------------------------------------
///
///
/// ->AbsoluteReliabilityFunction---> getInputReliability()
/// | |
/// | V
/// Sensor Value ---| ReliabilityAndConfidenceCombinator -> next line
/// | A |
/// | | V
/// ->ConfidenceFunction
/// getPossibleIdentifiers()
///
///-----------------------------------------------------------------------------------
///
/// feedback
/// |
/// V
/// FeedbackSymbols
/// | -> History -------|
/// V | V
/// here -> LikelinessFeedbackCombinator
/// ------>LikelinessHistoryCombinator->next line
/// | |
/// V V
/// getpossibleIdentifiersWithMasterFeedback() SymbolsWithHistory()
///
///----------------------------------------------------------------------------------
///
/// here -> sort -> most likely -> bestSymbol()
///
///---------------------------------------------------------------------------------
/// \endverbatim
/// the mentioned methods are early outs so if two ore more of them are run in
/// the same step they will be interpreted as different time steps
/// <pre>
/// Default values for Combinators:
/// AbsoluteAndSlopeReliabilityCombinationMethod =
/// combinationMin;
/// ReliabilityAndConfidenceCombinator=ReliabilityAndConfidenceCombinatorMin;
/// LikelinessFeedbackCombinator =
/// LikelinessFeedbackCombinatorAverage; LikelinessHistoryCombinator
/// = LikelinessHistoryCombinatorMax;
/// </pre>
/// To understand the place where the combinator methods come into play a list
/// for each early exit and which Methods are used.
///
/// <pre>
/// \c getInputReliability():
/// -AbsoluteAndSlopeReliabilityCombinationMethod
/// \c getPossibleIdentifiers():
/// -AbsoluteAndSlopeReliabilityCombinationMethod
/// -ReliabilityAndConfidenceCombinator
/// \c getpossibleIdentifiersWithMasterFeedback():
/// -AbsoluteAndSlopeReliabilityCombinationMethod
/// -ReliabilityAndConfidenceCombinator
/// -LikelinessFeedbackCombinator
/// \c SymbolsWithHistory():
/// -AbsoluteAndSlopeReliabilityCombinationMethod
/// -ReliabilityAndConfidenceCombinator
/// -LikelinessFeedbackCombinator
/// -LikelinessHistoryCombinator
/// \c bestSymbol():
/// -AbsoluteAndSlopeReliabilityCombinationMethod
/// -ReliabilityAndConfidenceCombinator
/// -LikelinessFeedbackCombinator
/// -LikelinessHistoryCombinator
/// </pre>
template <typename ValueType, typename IdentifierType, typename ReliabilityType>
class ReliabilityAndConfidenceCombinator {
public:
static_assert(std::is_arithmetic<ValueType>::value,
"LowLevel: ValueType has to an arithmetic type\n");
static_assert(std::is_arithmetic<IdentifierType>::value,
"LowLevel: IdentifierType has to an arithmetic type\n");
static_assert(std::is_arithmetic<ReliabilityType>::value,
"LowLevel: ReliabilityType has to an arithmetic type\n");
/// Typedef to shorten the writing.
/// \c Symbol
using Symbol = Symbol<IdentifierType, ReliabilityType>;
/// Calculates the input Reliability by combining Reliability of the Sensor
/// and the Slope Reliability \param SensorValue The sensor Value \note to set
/// the combination method \c
/// setAbsoluteAndSlopeReliabilityCombinationMethod()
ReliabilityType getInputReliability(const ValueType &SensorValue) noexcept {
ReliabilityType inputReliability =
getReliability(SensorValue, previousSensorValue, timeStep);
previousSensorValue = SensorValue;
PreviousSensorValueExists = true;
return inputReliability;
}
/// Calculates the possible Identifiers
/// \param SensorValue the Sensor Value
/// \brief it combines the input reliability and the confidence of the Sensor.
/// The use combination method can be set using \c
/// setReliabilityAndConfidenceCombinator()
std::vector<Symbol>
getPossibleIdentifiers(const ValueType &SensorValue) noexcept {
std::vector<Symbol> possibleIdentifiers;
ReliabilityType inputReliability = getInputReliability(SensorValue);
#if Reliability_trace_level <= trace_vectors
LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end;
#endif
possibleIdentifiers << ConfidenceFunction->operator()(SensorValue);
possibleIdentifiers = ReliabilityAndConfidenceCombinator(
possibleIdentifiers, inputReliability);
return possibleIdentifiers;
}
/// return the Possible Values with the feedback in mind
/// \param SensorValue The sensor Value
/// \brief it combines the input reliability and the confidence of the Sensor.
/// The combines them with LikelinessFeedbackCombinator and returns the
/// result.
std::vector<Symbol> getpossibleIdentifiersWithMasterFeedback(
const ValueType &SensorValue) noexcept {
std::vector<Symbol> possibleIdentifiers;
ReliabilityType inputReliability = getInputReliability(SensorValue);
#if Reliability_trace_level <= trace_vectors
LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end;
#endif
possibleIdentifiers << ConfidenceFunction->operator()(SensorValue);
possibleIdentifiers = ReliabilityAndConfidenceCombinator(
possibleIdentifiers, inputReliability);
possibleIdentifiers =
LikelinessFeedbackCombinator(possibleIdentifiers, FeedbackSymbols);
return possibleIdentifiers;
}
/// returns all possible Identifiers and Reliabilities with the History in
/// mind \param SensorValue the Sensor value how this is done is described at
/// the class.
std::vector<Symbol>
SymbolsWithHistory(const ValueType &SensorValue) noexcept {
std::vector<Symbol> ActuallPossibleIdentifiers;
std::vector<Symbol> possibleIdentifiers;
ReliabilityType inputReliability = getInputReliability(SensorValue);
#if Reliability_trace_level <= trace_vectors
LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end;
#endif
possibleIdentifiers << ConfidenceFunction->operator()(SensorValue);
possibleIdentifiers = ReliabilityAndConfidenceCombinator(
possibleIdentifiers, inputReliability);
possibleIdentifiers =
LikelinessFeedbackCombinator(possibleIdentifiers, FeedbackSymbols);
saveInHistory(possibleIdentifiers);
#if Reliability_trace_level <= trace_vectors
LOG_TRACE_STREAM << "\nActuallPossibleIdentifiers:\n"
<< possibleIdentifiers << trace_end;
LOG_TRACE_STREAM << "\npossibleIdentifiers:\n"
<< possibleIdentifiers << trace_end;
#endif
possibleIdentifiers.clear();
return SymbolsFromHistory();
}
/// Calculates the Reliability
/// \param SensorValue The current Values of the Sensor
///
/// \return Reliability and Identifier of the current SensorValue
///
Symbol bestSymbol(const ValueType &SensorValue) noexcept {
#if Reliability_trace_level <= trace_outputs
LOG_TRACE_STREAM << "\nTrace level is set to: " << Reliability_trace_level
<< "\n"
<< "Will trace: "
<< ((Reliability_trace_level == trace_outputs)
? "outputs"
: (Reliability_trace_level == trace_vectors)
? "vectors"
: (Reliability_trace_level ==
trace_everything)
? "everything"
: "undefined")
<< trace_end;
#endif
std::vector<Symbol> ActuallPossibleIdentifiers;
std::vector<Symbol> possibleIdentifiers;
ReliabilityType inputReliability = getInputReliability(SensorValue);
#if Reliability_trace_level <= trace_vectors
LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end;
#endif
possibleIdentifiers << ConfidenceFunction->operator()(SensorValue);
possibleIdentifiers = ReliabilityAndConfidenceCombinator(
possibleIdentifiers, inputReliability);
possibleIdentifiers =
LikelinessFeedbackCombinator(possibleIdentifiers, FeedbackSymbols);
saveInHistory(possibleIdentifiers);
#if Reliability_trace_level <= trace_vectors
LOG_TRACE_STREAM << "\nActuallPossibleIdentifiers:\n"
<< possibleIdentifiers << trace_end;
LOG_TRACE_STREAM << "\npossibleIdentifiers:\n"
<< possibleIdentifiers << trace_end;
#endif
possibleIdentifiers.clear();
possibleIdentifiers = SymbolsFromHistory();
std::sort(
possibleIdentifiers.begin(), possibleIdentifiers.end(),
[](Symbol A, Symbol B) -> bool { return A.Likeliness > B.Likeliness; });
#if Reliability_trace_level <= trace_outputs
LOG_TRACE_STREAM << "\noutput lowlevel: " << possibleIdentifiers.at(0)
<< trace_end;
#endif
return possibleIdentifiers.at(0);
}
/// feedback for this functionality most commonly it comes from a Master Agent
/// \param _FeedbackSymbols The Identifiers + Reliability for the feedback
/// \brief This input kind of resembles a confidence but not
/// directly it more or less says: compared to the other Identifiers inside
/// the System these are the Identifiers with the Reliability that you have.
void feedback(
const std::vector<Symbol>
&_FeedbackSymbols) noexcept // it is being copied internally anyway
{
FeedbackSymbols = _FeedbackSymbols;
}
//
// ----------------------Reliability and Confidence Function setters----------
//
/// This is the setter for Confidence Function
/// \param _ConfidenceFunction A pointer to the Functional for the
/// \c Confidence of the Sensor value
void setConfidenceFunction(
std::shared_ptr<
RangeConfidence<ReliabilityType, IdentifierType, ValueType>>
&_ConfidenceFunction) noexcept {
ConfidenceFunction = _ConfidenceFunction;
}
/// This is the setter for AbsoluteReliabilityFunction
/// \param _AbsoluteReliabilityFunction A pointer to the Functional for the
/// AbsoluteReliabilityFunction \brief The AbsoluteReliabilityFunction takes
/// the current Sensor value and return the AbsoluteReliabilityFunction of the
/// value.
void setAbsoluteReliabilityFunction(
std::shared_ptr<Abstraction<ValueType, ReliabilityType>>
&_AbsoluteReliabilityFunction) noexcept {
AbsoluteReliabilityFunction = _AbsoluteReliabilityFunction;
}
/// This is the setter for ReliabilitySlopeFunction Function
/// \param _ReliabilitySlopeFunction A pointer to the Functional for the
/// ReliabilitySlopeFunction
/// \brief The ReliabilitySlopeFunction takes the difference of the current
/// Sensor Value to the last one and tells you how likely the change is.
void setReliabilitySlopeFunction(
std::shared_ptr<Abstraction<ValueType, ReliabilityType>>
&_ReliabilitySlopeFunction) noexcept {
ReliabilitySlopeFunction = _ReliabilitySlopeFunction;
}
/// This is the setter for TimeFunctionForLikeliness Function
/// \param _TimeFunctionForLikeliness A pointer to the Functional for the
/// TimeFunctionForLikeliness \brief The time function takes the position in
/// the History with greater equals older and return a Reliability of how
/// "relevant" it is.
void setTimeFunctionForLikelinessFunction(
std::shared_ptr<Abstraction<std::size_t, ReliabilityType>>
&_TimeFunctionForLikeliness) noexcept {
TimeFunctionForLikeliness = _TimeFunctionForLikeliness;
}
/// This is the setter for all possible Identifiers
/// \param Identifiers A vector containing all Identifiers
/// \brief This exists even though \c Identifier Type is an arithmetic Type
/// because the Identifiers do not need to be "next" to each other ( ex.
/// Identifiers={ 1 7 24 })
void setIdentifiers(const std::vector<IdentifierType> &Identifiers) noexcept {
this->Identifiers = Identifiers;
}
/// This sets the Maximum length of the History
/// \param length The length
void setHistoryLength(const std::size_t &length) noexcept {
this->HistoryMaxSize = length;
}
/// This sets the Value set Counter
/// \param timeStep the new Value
/// \note This might actually be only an artifact. It is only used to get the
/// reliability from the \c ReliabilitySlopeFunction [
/// ReliabilitySlopeFunction->operator()( (lastValue - actualValue) /
/// (ValueType)timeStep) ]
void setTimeStep(const unsigned int &timeStep) noexcept {
this->timeStep = timeStep;
}
//
// ----------------combinator setters-----------------------------------------
//
/// This sets the combination method used by the History
/// \param Meth the method which should be used. predefined inside the \c
/// predefinedMethods struct LikelinessHistoryCombinator<method>()
void setLikelinessHistoryCombinator(
const std::function<ReliabilityType(ReliabilityType, ReliabilityType)>
&Meth) noexcept {
LikelinessHistoryCombinator = Meth;
}
/// sets the predefined method for the combination of the possible Identifiers
/// and the master
/// \param Meth the method which should be used. predefined inside the \c
/// predefinedMethods struct LikelinessFeedbackCombinator<method>()
void setLikelinessFeedbackCombinator(
const std::function<std::vector<Symbol>(
std::vector<Symbol>, std::vector<Symbol>)> &Meth) noexcept {
LikelinessFeedbackCombinator = Meth;
}
/// Sets the used combination method for Possible Identifiers
/// \param Meth the method which should be used. predefined inside the \c
/// predefinedMethods struct setReliabilityAndConfidenceCombinator<method>()
void setReliabilityAndConfidenceCombinator(
const std::function<std::vector<Symbol>(
std::vector<Symbol>, ReliabilityType)> &Meth) noexcept {
ReliabilityAndConfidenceCombinator = Meth;
}
/// sets the input reliability combinator method
/// \param method the method which should be used. predefined inside the \c
/// predefinedMethods struct combination<method>()
void setAbsoluteAndSlopeReliabilityCombinationMethod(
const std::function<ReliabilityType(ReliabilityType, ReliabilityType)>
&&method) noexcept {
AbsoluteAndSlopeReliabilityCombinationMethod = method;
}
//
// ----------------predefined combinators------------------------------------
//
/// This struct is a pseudo name space to have easier access to all predefined
/// methods while still not overcrowding the class it self
struct predefinedMethods {
/// predefined Method
static ReliabilityType
LikelinessHistoryCombinatorMin(ReliabilityType A,
ReliabilityType B) noexcept {
return std::min(A, B);
}
/// predefined Method
static ReliabilityType
LikelinessHistoryCombinatorMax(ReliabilityType A,
ReliabilityType B) noexcept {
return std::max(A, B);
}
/// predefined Method
static ReliabilityType
LikelinessHistoryCombinatorMult(ReliabilityType A,
ReliabilityType B) noexcept {
return A * B;
}
/// predefined Method
static ReliabilityType
LikelinessHistoryCombinatorAverage(ReliabilityType A,
ReliabilityType B) noexcept {
return (A + B) / 2;
}
/// predefined method
static std::vector<Symbol>
LikelinessFeedbackCombinatorAverage(std::vector<Symbol> A,
std::vector<Symbol> B) noexcept {
for (auto &tmp_me : A)
for (auto &tmp_other : B) {
if (tmp_me.Identifier == tmp_other.Identifier) {
tmp_me.Likeliness = (tmp_me.Likeliness + tmp_other.Likeliness) / 2;
}
}
return A;
}
/// predefined method
static std::vector<Symbol>
LikelinessFeedbackCombinatorMin(std::vector<Symbol> A,
std::vector<Symbol> B) noexcept {
for (auto &tmp_me : A)
for (auto &tmp_other : B) {
if (tmp_me.Identifier == tmp_other.Identifier) {
tmp_me.Likeliness =
std::min(tmp_me.Likeliness + tmp_other.Likeliness);
}
}
return A;
}
/// predefined method
static std::vector<Symbol>
LikelinessFeedbackCombinatorMax(std::vector<Symbol> A,
std::vector<Symbol> B) noexcept {
for (auto &tmp_me : A)
for (auto &tmp_other : B) {
if (tmp_me.Identifier == tmp_other.Identifier) {
tmp_me.Likeliness =
std::max(tmp_me.Likeliness + tmp_other.Likeliness);
}
}
return A;
}
/// predefined method
static std::vector<Symbol>
LikelinessFeedbackCombinatorMult(std::vector<Symbol> A,
std::vector<Symbol> B) noexcept {
for (auto &tmp_me : A)
for (auto &tmp_other : B) {
if (tmp_me.Identifier == tmp_other.Identifier) {
tmp_me.Likeliness = tmp_me.Likeliness * tmp_other.Likeliness;
}
}
return A;
}
/// Predefined combination method for possible Identifiers
static std::vector<Symbol>
ReliabilityAndConfidenceCombinatorMin(std::vector<Symbol> A,
ReliabilityType B) noexcept {
for (auto tmp : A)
tmp.Likeliness = std::min(tmp.Likeliness, B);
return A;
}
/// Predefined combination method for possible Identifiers
static std::vector<Symbol>
ReliabilityAndConfidenceCombinatorMax(std::vector<Symbol> A,
ReliabilityType B) noexcept {
for (auto tmp : A)
tmp.Likeliness = std::max(tmp.Likeliness, B);
return A;
}
/// Predefined combination method for possible Identifiers
static std::vector<Symbol>
ReliabilityAndConfidenceCombinatorAverage(std::vector<Symbol> A,
ReliabilityType B) noexcept {
for (auto tmp : A)
tmp.Likeliness = (tmp.Likeliness + B) / 2;
return A;
}
/// Predefined combination method for possible Identifiers
static std::vector<Symbol>
ReliabilityAndConfidenceCombinatorMult(std::vector<Symbol> A,
ReliabilityType B) noexcept {
for (auto tmp : A)
tmp.Likeliness = tmp.Likeliness * B / 2;
return A;
}
/// The predefined min combinator method
static ReliabilityType combinationMin(ReliabilityType A,
ReliabilityType B) noexcept {
return std::min(A, B);
}
/// The predefined max combinator method
static ReliabilityType combinationMax(ReliabilityType A,
ReliabilityType B) noexcept {
return std::max(A, B);
}
/// The predefined average combinator method
static ReliabilityType combinationAverage(ReliabilityType A,
ReliabilityType B) noexcept {
return (A + B) / 2;
}
/// The predefined average combinator method
static ReliabilityType combinationMult(ReliabilityType A,
ReliabilityType B) noexcept {
return A * B;
}
};
// ----------------------------------------------------------------
// Stored Values
// ----------------------------------------------------------------
private:
std::vector<std::vector<Symbol>> History;
std::size_t HistoryMaxSize;
std::vector<Symbol> FeedbackSymbols;
ValueType previousSensorValue;
unsigned int timeStep;
std::vector<IdentifierType> Identifiers;
bool PreviousSensorValueExists = false;
std::shared_ptr<RangeConfidence<ReliabilityType, IdentifierType, ValueType>>
ConfidenceFunction;
std::shared_ptr<Abstraction<ValueType, ReliabilityType>>
AbsoluteReliabilityFunction;
std::shared_ptr<Abstraction<ValueType, ReliabilityType>>
ReliabilitySlopeFunction;
std::shared_ptr<Abstraction<std::size_t, ReliabilityType>>
TimeFunctionForLikeliness;
// combination functions
std::function<ReliabilityType(ReliabilityType, ReliabilityType)>
AbsoluteAndSlopeReliabilityCombinationMethod =
predefinedMethods::combinationMin;
std::function<std::vector<Symbol>(std::vector<Symbol>, ReliabilityType)>
ReliabilityAndConfidenceCombinator =
predefinedMethods::ReliabilityAndConfidenceCombinatorMin;
std::function<std::vector<Symbol>(std::vector<Symbol>, std::vector<Symbol>)>
LikelinessFeedbackCombinator =
predefinedMethods::LikelinessFeedbackCombinatorAverage;
std::function<ReliabilityType(ReliabilityType, ReliabilityType)>
LikelinessHistoryCombinator =
predefinedMethods::LikelinessHistoryCombinatorMax;
// ---------------------------------------------------------------------------
// needed Functions
// ---------------------------------------------------------------------------
/// returns the Reliability
/// \param actualValue The Value of the Sensor
/// \param lastValue of the Sensor this is stored in the class
/// \param _timeStep It has an effect on the difference of the current
/// and last value This might not be needed anymore
/// \brief it returns the combination the \c Reliability function and \c
/// ReliabilitySlopeFunction if the previous value exists. if it doesn't it
/// only returns the \c Reliability function value.
ReliabilityType getReliability(const ValueType &actualValue,
const ValueType &lastValue,
const unsigned int &_timeStep) noexcept {
ReliabilityType relAbs =
AbsoluteReliabilityFunction->operator()(actualValue);
if (PreviousSensorValueExists) {
ReliabilityType relSlo = ReliabilitySlopeFunction->operator()(
(lastValue - actualValue) / static_cast<ValueType>(_timeStep)); //
return AbsoluteAndSlopeReliabilityCombinationMethod(relAbs, relSlo);
} else
return relAbs;
}
/// adapts the possible Identifiers by checking the History and combines those
/// values.
/// \brief combines the historic values with the \c TimeFunctionForLikeliness
/// function and returns the maximum Reliability for all Identifiers.
std::vector<Symbol> SymbolsFromHistory() noexcept {
// iterate through all history entries
std::size_t posInHistory = 0;
std::vector<Symbol> symbolFromHistory; // History Symbols
for (auto timeStep = History.begin(); timeStep < History.end();
timeStep++, posInHistory++) {
// iterate through all possible Identifiers of each history entry
for (Symbol &symbol : *timeStep) {
IdentifierType historyIdentifier = symbol.Identifier;
ReliabilityType historyConf = symbol.Likeliness;
historyConf =
historyConf * TimeFunctionForLikeliness->operator()(posInHistory);
bool foundIdentifier = false;
for (Symbol &pS : symbolFromHistory) {
if (pS.Identifier == historyIdentifier) {
pS.Likeliness =
LikelinessHistoryCombinator(pS.Likeliness, historyConf);
foundIdentifier = true;
}
}
if (foundIdentifier == false) {
Symbol possibleIdentifier; // Symbol
possibleIdentifier.Identifier = historyIdentifier;
possibleIdentifier.Likeliness = historyConf;
symbolFromHistory.push_back(possibleIdentifier);
}
}
}
return symbolFromHistory;
}
/// saves the Identifiers in the History
/// \brief It checks the incoming Identifiers if any have a Reliability
/// greater than 0.5 all of them get saved inside the History and then the
/// History get shortened to the maximal length. It only saves the Value if
/// the History is empty.
///
/// \param actualPossibleIdentifiers The Identifiers which should be saved
///
/// \note Does the History really make sense if the values are to small it
/// only stores something if it's empty and not if it isn't completely filled
void saveInHistory(const std::vector<Symbol>
&actualPossibleIdentifiers) noexcept { // Symbols
// check if the reliability of at least one possible Identifier is high
// enough
bool atLeastOneRelIsHigh = false;
for (Symbol pS : actualPossibleIdentifiers) {
if (pS.Likeliness > 0.5) {
atLeastOneRelIsHigh = true;
}
}
// save possible Identifiers if at least one possible Identifier is high
// enough (or if the history is empty)
if (History.size() < 1 || atLeastOneRelIsHigh == true) {
History.insert(History.begin(), actualPossibleIdentifiers);
// if history size is higher than allowed, save oldest element
while (History.size() > HistoryMaxSize) {
// delete possibleIdentifierHistory.back();
History.pop_back();
}
}
}
};
} // namespace agent
} // namespace rosa
#endif // !ROSA_AGENT_ReliabilityConfidenceCombinator_H
diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp
index cb42b54..4abbb5d 100644
--- a/include/rosa/agent/SignalState.hpp
+++ b/include/rosa/agent/SignalState.hpp
@@ -1,511 +1,511 @@
//===-- rosa/agent/SignalState.hpp ------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/SignalState.hpp
///
/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *signal state* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_SIGNALSTATE_HPP
#define ROSA_AGENT_SIGNALSTATE_HPP
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/Functionality.h"
#include "rosa/agent/History.hpp"
#include "rosa/agent/State.hpp"
#include "rosa/support/math.hpp"
namespace rosa {
namespace agent {
/// Signal properties defining the properties of the signal which is monitored
/// by \c rosa::agent::SignalStateDetector and is saved in \c
/// rosa::agent::SignalStateInformation.
enum SignalProperties : uint8_t {
INPUT = 0, ///< The signal is an input signal
OUTPUT = 1 ///< The signal is an output signal
};
/// TODO: write description
template <typename CONFDATATYPE>
struct SignalStateInformation : StateInformation<CONFDATATYPE> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence type is not to arithmetic");
/// ConfidenceOfMatchingState is the confidence how good the new sample
/// matches the state.
CONFDATATYPE ConfidenceOfMatchingState;
/// ConfidenceOfMatchingState is the confidence how bad the new sample
/// matches the state.
CONFDATATYPE ConfidenceOfMismatchingState;
/// The SignalProperty saves whether the monitored signal is an input our
/// output signal.
SignalProperties SignalProperty;
/// The SignalStateIsValid saves the number of samples which have been
/// inserted into the state after entering it.
uint32_t NumberOfInsertedSamplesAfterEntrance;
public:
SignalStateInformation(unsigned int SignalStateID,
SignalProperties _SignalProperty) {
this->StateID = SignalStateID;
this->SignalProperty = _SignalProperty;
this->StateCondition = StateConditions::UNKNOWN;
this->NumberOfInsertedSamplesAfterEntrance = 0;
this->StateIsValid = false;
this->StateJustGotValid = false;
this->StateIsValidAfterReentrance = false;
this->ConfidenceStateIsValid = 0;
this->ConfidenceStateIsInvalid = 0;
this->ConfidenceStateIsStable = 0;
this->ConfidenceStateIsDrifting = 0;
}
- SignalStateInformation() {}
+ SignalStateInformation() = default;
};
/// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of
/// data in that the confidence values are given, \tparam PROCDATATYPE type of
/// the relative distance and the type of data in which DABs are saved.
template <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE>
class SignalState : public Functionality {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<INDATATYPE>::value),
"input data type not arithmetic");
STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence data type is not to arithmetic");
STATIC_ASSERT(
(std::is_arithmetic<PROCDATATYPE>::value),
"process data type (DAB and Relative Distance) is not to arithmetic");
public:
// For the convinience to write a shorter data type name
using PartFuncReference = PartialFunction<INDATATYPE, CONFDATATYPE> &;
using StepFuncReference = StepFunction<INDATATYPE, CONFDATATYPE> &;
private:
/// SignalStateInfo is a struct of SignalStateInformation that contains
/// information about the current signal state.
SignalStateInformation<CONFDATATYPE> SignalStateInfo;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// confidence how good the new sample matches another sample in the sample
/// history.
PartFuncReference FuzzyFunctionSampleMatches;
/// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the
/// confidence how bad the new sample matches another sample in the sample
/// history.
PartFuncReference FuzzyFunctionSampleMismatches;
/// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
StepFuncReference FuzzyFunctionNumOfSamplesMatches;
/// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives
/// the confidence how many samples from the sampe history mismatch the new
/// sample.
StepFuncReference FuzzyFunctionNumOfSamplesMismatches;
/// The FuzzyFunctionSampleValid is the fuzzy function that gives the
/// confidence how good one matches another sample in the sample
/// history. This is done to evaluate whether a state is valid.
PartFuncReference FuzzyFunctionSampleValid;
/// The FuzzyFunctionSampleInvalid is the fuzzy function that gives the
/// confidence how bad one sample matches another sample in the sample
/// history. This is done to evaluate whether a state is invalid.
PartFuncReference FuzzyFunctionSampleInvalid;
/// The FuzzyFunctionNumOfSamplesValid is the fuzzy function that gives the
/// confidence how many samples from the sample history match another sample.
/// This is done to evaluate whether a state is valid.
StepFuncReference FuzzyFunctionNumOfSamplesValid;
/// The FuzzyFunctionNumOfSamplesInvalid is the fuzzy function that gives
/// the confidence how many samples from the sample history mismatch another
/// sample. This is done to evaluate whether a state is invalid.
StepFuncReference FuzzyFunctionNumOfSamplesInvalid;
/// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the
/// confidence how likely it is that the signal (resp. the state of a signal)
/// is drifting.
PartFuncReference FuzzyFunctionSignalIsDrifting;
/// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the
/// confidence how likely it is that the signal (resp. the state of a signal)
/// is stable (not drifting).
PartFuncReference FuzzyFunctionSignalIsStable;
/// SampleHistory is a history in that the last sample values are stored.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO> SampleHistory;
/// DAB is a (usually) small history of the last sample values of which a
/// average is calculated if the DAB is full.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::SRWF> DAB;
/// DABHistory is a history in that the last DABs (to be exact, the averages
/// of the last DABs) are stored.
DynamicLengthHistory<PROCDATATYPE, HistoryPolicy::LIFO> DABHistory;
/// LowestConfidenceMatchingHistory is a history in that the lowest confidence
/// for the current sample matches all history samples are saved.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO>
LowestConfidenceMatchingHistory;
/// HighestConfidenceMatchingHistory is a history in that the highest
/// confidence for the current sample matches all history samples are saved.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO>
HighestConfidenceMismatchingHistory;
/// TempConfidenceMatching is the confidence how good a sample matches the
/// state. However, the value of this variable is only needed temporarly.
CONFDATATYPE TempConfidenceMatching = 0;
/// TempConfidenceMatching is the confidence how bad a sample matches the
/// state. However, the value of this variable is only needed temporarly.
CONFDATATYPE TempConfidenceMismatching = 0;
public:
/// Creates an instance by setting all parameters
/// \param SignalStateID The Id of the SignalStateinfo \c
/// SignalStateInformation.
///
/// \param FuzzyFunctionSampleMatches The FuzzyFunctionSampleMatches is the
/// fuzzy function that gives the confidence how good the new sample matches
/// another sample in the sample history.
///
/// \param FuzzyFunctionSampleMismatches The FuzzyFunctionSampleMismatches is
/// the fuzzy function that gives the confidence how bad the new sample
/// matches another sample in the sample history.
///
/// \param FuzzyFunctionNumOfSamplesMatches The
/// FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
///
/// \param FuzzyFunctionNumOfSamplesMismatches The
/// FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history mismatch the new
/// sample.
///
/// \param FuzzyFunctionSignalIsDrifting The FuzzyFunctionSignalIsDrifting is
/// the fuzzy function that gives the confidence how likely it is that the
/// signal (resp. the state of a signal) is drifting.
///
/// \param FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the
/// fuzzy function that gives the confidence how likely it is that the signal
/// (resp. the state of a signal) is stable (not drifting).
///
/// \param SampleHistorySize Size of the Sample History \c
/// DynamicLengthHistory . SampleHistory is a history in that the last sample
/// values are stored.
///
/// \param DABSize Size of DAB \c DynamicLengthHistory . DAB is a (usually)
/// small history of the last sample values of which a average is calculated
/// if the DAB is full.
///
/// \param DABHistorySize Size of the DABHistory \c DynamicLengthHistory .
/// DABHistory is a history in that the last DABs (to be exact, the averages
/// of the last DABs) are stored.
///
SignalState(uint32_t SignalStateID, SignalProperties SignalProperty,
uint32_t SampleHistorySize, uint32_t DABSize,
uint32_t DABHistorySize,
PartFuncReference FuzzyFunctionSampleMatches,
PartFuncReference FuzzyFunctionSampleMismatches,
StepFuncReference FuzzyFunctionNumOfSamplesMatches,
StepFuncReference FuzzyFunctionNumOfSamplesMismatches,
PartFuncReference FuzzyFunctionSampleValid,
PartFuncReference FuzzyFunctionSampleInvalid,
StepFuncReference FuzzyFunctionNumOfSamplesValid,
StepFuncReference FuzzyFunctionNumOfSamplesInvalid,
PartFuncReference FuzzyFunctionSignalIsDrifting,
PartFuncReference FuzzyFunctionSignalIsStable) noexcept
: SignalStateInfo{SignalStateID, SignalProperty},
FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches),
FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches),
FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches),
FuzzyFunctionNumOfSamplesMismatches(
FuzzyFunctionNumOfSamplesMismatches),
FuzzyFunctionSampleValid(FuzzyFunctionSampleValid),
FuzzyFunctionSampleInvalid(FuzzyFunctionSampleInvalid),
FuzzyFunctionNumOfSamplesValid(FuzzyFunctionNumOfSamplesValid),
FuzzyFunctionNumOfSamplesInvalid(FuzzyFunctionNumOfSamplesInvalid),
FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting),
FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable),
SampleHistory(SampleHistorySize), DAB(DABSize),
DABHistory(DABHistorySize),
LowestConfidenceMatchingHistory(SampleHistorySize),
HighestConfidenceMismatchingHistory(SampleHistorySize) {}
/// Destroys \p this object.
~SignalState(void) = default;
void leaveSignalState(void) noexcept {
DAB.clear();
SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0;
SignalStateInfo.StateIsValidAfterReentrance = false;
}
SignalStateInformation<CONFDATATYPE>
insertSample(INDATATYPE Sample) noexcept {
SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++;
validateSignalState(Sample);
SampleHistory.addEntry(Sample);
DAB.addEntry(Sample);
if (DAB.full()) {
PROCDATATYPE AvgOfDAB = DAB.template average<PROCDATATYPE>();
DABHistory.addEntry(AvgOfDAB);
DAB.clear();
}
FuzzyFunctionNumOfSamplesMatches.setRightLimit(
static_cast<INDATATYPE>(SampleHistory.numberOfEntries()));
FuzzyFunctionNumOfSamplesMismatches.setRightLimit(
static_cast<INDATATYPE>(SampleHistory.numberOfEntries()));
checkSignalStability();
SignalStateInfo.ConfidenceOfMatchingState = TempConfidenceMatching;
SignalStateInfo.ConfidenceOfMismatchingState = TempConfidenceMismatching;
return SignalStateInfo;
}
/// Gives the confidence how likely the new sample matches the signal state.
///
/// \param Sample is the actual sample of the observed signal.
///
/// \return the confidence of the new sample is matching the signal state.
CONFDATATYPE
confidenceSampleMatchesSignalState(INDATATYPE Sample) noexcept {
CONFDATATYPE ConfidenceOfBestCase = 0;
DynamicLengthHistory<PROCDATATYPE, HistoryPolicy::FIFO>
RelativeDistanceHistory(SampleHistory.maxLength());
// Calculate distances to all history samples.
for (auto &HistorySample : SampleHistory) {
PROCDATATYPE RelativeDistance =
relativeDistance<INDATATYPE, PROCDATATYPE>(Sample, HistorySample);
RelativeDistanceHistory.addEntry(RelativeDistance);
}
// Sort all calculated distances so that the lowest distance (will get the
// highest confidence) is at the beginning.
RelativeDistanceHistory.sortAscending();
CONFDATATYPE ConfidenceOfWorstFittingSample = 1;
// Case 1 means that one (the best fitting) sample of the history is
// compared with the new sample. Case 2 means the two best history samples
// are compared with the new sample. And so on.
// TODO (future): to accelerate . don't start with 1 start with some higher
// number because a low number (i guess lower than 5) will definetely lead
// to a low confidence. except the history is not full.
// Case 1 means that one (the best fitting) sample of the history is
// compared with the new sample. Case 2 means the two best history samples
// are compared with the new sample. And so on.
for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries();
Case++) {
CONFDATATYPE ConfidenceFromRelativeDistance;
if (std::isinf(RelativeDistanceHistory[Case])) {
// TODO (future): if fuzzy is defined in a way that infinity is not 0 it
// would be a problem.
ConfidenceFromRelativeDistance = 0;
} else {
ConfidenceFromRelativeDistance =
FuzzyFunctionSampleMatches(RelativeDistanceHistory[Case]);
}
ConfidenceOfWorstFittingSample = fuzzyAND(ConfidenceOfWorstFittingSample,
ConfidenceFromRelativeDistance);
ConfidenceOfBestCase =
fuzzyOR(ConfidenceOfBestCase,
fuzzyAND(ConfidenceOfWorstFittingSample,
FuzzyFunctionNumOfSamplesMatches(
static_cast<CONFDATATYPE>(Case) + 1)));
}
TempConfidenceMatching = ConfidenceOfBestCase;
return ConfidenceOfBestCase;
}
/// Gives the confidence how likely the new sample mismatches the signal
/// state.
///
/// \param Sample is the actual sample of the observed signal.
///
/// \return the confidence of the new sample is mismatching the signal state.
CONFDATATYPE
confidenceSampleMismatchesSignalState(INDATATYPE Sample) noexcept {
float ConfidenceOfWorstCase = 1;
DynamicLengthHistory<PROCDATATYPE, HistoryPolicy::FIFO>
RelativeDistanceHistory(SampleHistory.maxLength());
// Calculate distances to all history samples.
for (auto &HistorySample : SampleHistory) {
RelativeDistanceHistory.addEntry(
relativeDistance<INDATATYPE, PROCDATATYPE>(Sample, HistorySample));
}
// Sort all calculated distances so that the highest distance (will get the
// lowest confidence) is at the beginning.
RelativeDistanceHistory.sortDescending();
CONFDATATYPE ConfidenceOfBestFittingSample = 0;
// TODO (future): to accelerate -> don't go until end. Confidences will only
// get higher. See comment in "CONFDATATYPE
// confidenceSampleMatchesSignalState(INDATATYPE Sample)".
// Case 1 means that one (the worst fitting) sample of the history is
// compared with the new sample. Case 2 means the two worst history samples
// are compared with the new sample. And so on.
for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries();
Case++) {
CONFDATATYPE ConfidenceFromRelativeDistance;
if (std::isinf(RelativeDistanceHistory[Case])) {
ConfidenceFromRelativeDistance = 1;
} else {
ConfidenceFromRelativeDistance =
FuzzyFunctionSampleMismatches(RelativeDistanceHistory[Case]);
}
ConfidenceOfBestFittingSample = fuzzyOR(ConfidenceOfBestFittingSample,
ConfidenceFromRelativeDistance);
ConfidenceOfWorstCase =
fuzzyAND(ConfidenceOfWorstCase,
fuzzyOR(ConfidenceOfBestFittingSample,
FuzzyFunctionNumOfSamplesMismatches(
static_cast<CONFDATATYPE>(Case) + 1)));
}
TempConfidenceMismatching = ConfidenceOfWorstCase;
return ConfidenceOfWorstCase;
}
/// Gives information about the current signal state.
///
/// \return a struct SignalStateInformation that contains information about
/// the current signal state.
SignalStateInformation<CONFDATATYPE> signalStateInformation(void) noexcept {
return SignalStateInfo;
}
private:
void validateSignalState(INDATATYPE Sample) {
// TODO (future): WorstConfidenceDistance and BestConfidenceDistance could
// be set already in "CONFDATATYPE
// confidenceSampleMatchesSignalState(INDATATYPE Sample)" and "CONFDATATYPE
// confidenceSampleMismatchesSignalState(INDATATYPE Sample)" when the new
// sample is compared to all history samples. This would save a lot time
// because the comparisons are done only once. However, it has to be asured
// that the these two functions are called before the insertation, and the
// FuzzyFunctions for validation and matching have to be the same!
CONFDATATYPE LowestConfidenceMatching = 1;
CONFDATATYPE HighestConfidenceMismatching = 0;
for (auto &HistorySample : SampleHistory) {
// TODO (future): think about using different fuzzy functions for
// validation and matching.
LowestConfidenceMatching = fuzzyAND(
LowestConfidenceMatching,
FuzzyFunctionSampleMatches(relativeDistance<INDATATYPE, PROCDATATYPE>(
Sample, HistorySample)));
HighestConfidenceMismatching =
fuzzyOR(HighestConfidenceMismatching,
FuzzyFunctionSampleMismatches(
relativeDistance<INDATATYPE, PROCDATATYPE>(
Sample, HistorySample)));
}
LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching);
HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching);
LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry();
HighestConfidenceMismatching =
HighestConfidenceMismatchingHistory.highestEntry();
SignalStateInfo.ConfidenceStateIsValid =
fuzzyAND(LowestConfidenceMatching,
FuzzyFunctionNumOfSamplesValid(static_cast<INDATATYPE>(
SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)));
SignalStateInfo.ConfidenceStateIsInvalid =
fuzzyOR(HighestConfidenceMismatching,
FuzzyFunctionNumOfSamplesInvalid(static_cast<INDATATYPE>(
SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)));
if (SignalStateInfo.ConfidenceStateIsValid >
SignalStateInfo.ConfidenceStateIsInvalid) {
if (SignalStateInfo.StateIsValid) {
SignalStateInfo.StateJustGotValid = false;
} else {
SignalStateInfo.StateJustGotValid = true;
}
SignalStateInfo.StateIsValid = true;
SignalStateInfo.StateIsValidAfterReentrance = true;
}
}
void checkSignalStability(void) {
if (DABHistory.numberOfEntries() >= 2) {
SignalStateInfo.ConfidenceStateIsStable = FuzzyFunctionSignalIsStable(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0]));
SignalStateInfo.ConfidenceStateIsDrifting = FuzzyFunctionSignalIsDrifting(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0]));
} else {
// Initializing the following variables because (at this moment) we do not
// know if the signal is stable or drifting.
SignalStateInfo.ConfidenceStateIsStable = 0;
SignalStateInfo.ConfidenceStateIsDrifting = 0;
}
if (SignalStateInfo.ConfidenceStateIsStable >
SignalStateInfo.ConfidenceStateIsDrifting) {
SignalStateInfo.StateCondition = StateConditions::STABLE;
} else if (SignalStateInfo.ConfidenceStateIsStable <
SignalStateInfo.ConfidenceStateIsDrifting) {
SignalStateInfo.StateCondition = StateConditions::DRIFTING;
} else {
SignalStateInfo.StateCondition = StateConditions::UNKNOWN;
}
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_SIGNALSTATE_HPP
diff --git a/include/rosa/agent/SystemState.hpp b/include/rosa/agent/SystemState.hpp
index 3d3774f..7bfe5ae 100644
--- a/include/rosa/agent/SystemState.hpp
+++ b/include/rosa/agent/SystemState.hpp
@@ -1,289 +1,289 @@
//===-- rosa/agent/SystemState.hpp ------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/SystemState.hpp
///
/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *system state* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_SYSTEMSTATE_HPP
#define ROSA_AGENT_SYSTEMSTATE_HPP
#include "rosa/agent/Functionality.h"
#include "rosa/agent/SignalState.hpp"
#include "rosa/agent/State.hpp"
#include "rosa/support/debug.hpp"
#include <vector>
namespace rosa {
namespace agent {
enum class SystemStateRelation : uint8_t {
STATEISMATCHING = 0, ///< The system state is matching
ONLYINPUTISMATCHING = 1, ///< Only inputs of the system state are matching
ONLYOUTPUTISMATCHING = 2, ///< Only outputs of the system state are matching
STATEISMISMATCHING = 3 ///< The system state is mismatching
};
/// TODO: write description
template <typename CONFDATATYPE>
struct SystemStateInformation : StateInformation<CONFDATATYPE> {
/// TODO: describe
CONFDATATYPE ConfidenceOfInputsMatchingState;
CONFDATATYPE ConfidenceOfInputsMismatchingState;
CONFDATATYPE ConfidenceOfOutputsMatchingState;
CONFDATATYPE ConfidenceOfOutputsMismatchingState;
CONFDATATYPE ConfidenceSystemIsFunctioning;
CONFDATATYPE ConfidenceSystemIsMalfunctioning;
CONFDATATYPE ConfidenceOfAllDecisions;
public:
- SystemStateInformation() {}
+ SystemStateInformation() = default;
SystemStateInformation(unsigned int _SystemStateID,
StateConditions _StateCondition) {
this->StateID = _SystemStateID;
this->StateCondition = _StateCondition;
this->StateIsValid = false;
this->StateJustGotValid = false;
this->StateIsValidAfterReentrance = false;
this->ConfidenceOfInputsMatchingState = 0;
this->ConfidenceOfInputsMismatchingState = 0;
this->ConfidenceOfOutputsMatchingState = 0;
this->ConfidenceOfOutputsMismatchingState = 0;
this->ConfidenceSystemIsFunctioning = 0;
this->ConfidenceSystemIsMalfunctioning = 0;
this->ConfidenceOfAllDecisions = 0;
}
};
// todo: do we need PROCDATATYPE?
/// TODO TEXT
template <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE>
class SystemState : public State<INDATATYPE, CONFDATATYPE, PROCDATATYPE> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT(std::is_arithmetic<INDATATYPE>::value,
"input data type is not to arithmetic");
STATIC_ASSERT(std::is_arithmetic<CONFDATATYPE>::value,
"confidence abstraction type is not to arithmetic");
STATIC_ASSERT(std::is_arithmetic<PROCDATATYPE>::value,
"process data type is not to arithmetic");
private:
/// SignalStateInfo is a struct of SignalStateInformation that contains
/// information about the current signal state.
SystemStateInformation<CONFDATATYPE> SystemStateInfo;
std::vector<SignalStateInformation<CONFDATATYPE>> SignalStateInfos;
uint32_t NumberOfSignals;
public:
/// TODO: write description
SystemState(uint32_t StateID, uint32_t NumberOfSignals) noexcept
: SystemStateInfo(StateID, StateConditions::UNKNOWN),
NumberOfSignals(NumberOfSignals) {
SignalStateInfos.resize(NumberOfSignals);
}
/// Destroys \p this object.
~SystemState(void) = default;
/// TODO: write description
SystemStateInformation<CONFDATATYPE> insertSignalStateInformation(
const std::vector<SignalStateInformation<CONFDATATYPE>>
_SignalStateInfos) noexcept {
ASSERT(_SignalStateInfos.size() == NumberOfSignals);
bool AllSignalsAreValid = true;
bool AtLeastOneSignalJustGotValid = false;
bool AllSignalsAreValidAfterReentrance = true;
bool AtLeastOneSignalIsUnknown = false;
bool AllSignalsAreStable = true;
// TODO: change this
SystemStateInfo.ConfidenceOfInputsMatchingState = 1;
SystemStateInfo.ConfidenceOfInputsMismatchingState = 0;
SystemStateInfo.ConfidenceOfOutputsMatchingState = 1;
SystemStateInfo.ConfidenceOfOutputsMismatchingState = 0;
SystemStateInfo.ConfidenceStateIsValid = 1;
SystemStateInfo.ConfidenceStateIsInvalid = 0;
SystemStateInfo.ConfidenceStateIsStable = 1;
SystemStateInfo.ConfidenceStateIsDrifting = 0;
std::size_t counter = 0;
for (auto SSI : _SignalStateInfos) {
if (!SSI.StateIsValid)
AllSignalsAreValid = false;
if (SSI.StateJustGotValid)
AtLeastOneSignalJustGotValid = true;
if (!SSI.StateIsValidAfterReentrance)
AllSignalsAreValidAfterReentrance = false;
if (SSI.StateCondition == StateConditions::UNKNOWN)
AtLeastOneSignalIsUnknown = true;
if (SSI.StateCondition == StateConditions::DRIFTING)
AllSignalsAreStable = false;
if (SSI.SignalProperty == SignalProperties::INPUT) {
SystemStateInfo.ConfidenceOfInputsMatchingState =
fuzzyAND(SystemStateInfo.ConfidenceOfInputsMatchingState,
SSI.ConfidenceOfMatchingState);
SystemStateInfo.ConfidenceOfInputsMismatchingState =
fuzzyOR(SystemStateInfo.ConfidenceOfInputsMismatchingState,
SSI.ConfidenceOfMismatchingState);
} else {
SystemStateInfo.ConfidenceOfOutputsMatchingState =
fuzzyAND(SystemStateInfo.ConfidenceOfOutputsMatchingState,
SSI.ConfidenceOfMatchingState);
SystemStateInfo.ConfidenceOfOutputsMismatchingState =
fuzzyOR(SystemStateInfo.ConfidenceOfOutputsMismatchingState,
SSI.ConfidenceOfMismatchingState);
}
SystemStateInfo.ConfidenceStateIsValid = fuzzyAND(
SystemStateInfo.ConfidenceStateIsValid, SSI.ConfidenceStateIsValid);
SystemStateInfo.ConfidenceStateIsInvalid =
fuzzyOR(SystemStateInfo.ConfidenceStateIsInvalid,
SSI.ConfidenceStateIsInvalid);
SystemStateInfo.ConfidenceStateIsStable = fuzzyAND(
SystemStateInfo.ConfidenceStateIsStable, SSI.ConfidenceStateIsStable);
SystemStateInfo.ConfidenceStateIsDrifting =
fuzzyOR(SystemStateInfo.ConfidenceStateIsDrifting,
SSI.ConfidenceStateIsDrifting);
this->SignalStateInfos.at(counter) = SSI;
counter++;
}
SystemStateInfo.StateIsValid = AllSignalsAreValid;
SystemStateInfo.StateJustGotValid =
AllSignalsAreValid && AtLeastOneSignalJustGotValid;
SystemStateInfo.StateIsValidAfterReentrance =
AllSignalsAreValidAfterReentrance;
if (AtLeastOneSignalIsUnknown)
SystemStateInfo.StateCondition = StateConditions::UNKNOWN;
else if (AllSignalsAreStable)
SystemStateInfo.StateCondition = StateConditions::STABLE;
else
SystemStateInfo.StateCondition = StateConditions::DRIFTING;
return SystemStateInfo;
}
/// TODO: write description
// TODO (future): think about saving the state information in a history
SystemStateRelation compareSignalStateInformation(
const std::vector<SignalStateInformation<CONFDATATYPE>>
_SignalStateInfos) noexcept {
bool inputsAreMatching = true;
bool outputsAreMatching = true;
std::size_t counter = 0;
for (auto SSI : _SignalStateInfos) {
if (this->SignalStateInfos.at(counter).StateID != SSI.StateID) {
if (SSI.SignalProperty == SignalProperties::INPUT)
inputsAreMatching = false;
else // SignalProperties::OUTPUT
outputsAreMatching = false;
}
counter++;
}
if (inputsAreMatching && outputsAreMatching)
return SystemStateRelation::STATEISMATCHING;
else if (inputsAreMatching && !outputsAreMatching)
return SystemStateRelation::ONLYINPUTISMATCHING;
else if (!inputsAreMatching && outputsAreMatching)
return SystemStateRelation::ONLYOUTPUTISMATCHING;
else
return SystemStateRelation::STATEISMISMATCHING;
}
#ifdef ADDITIONAL_FUNCTIONS
/// TODO: write description
template <std::size_t size>
void insertSignalStateInformation(
const std::array<SystemStateInformation<CONFDATATYPE>, size>
&Data) noexcept {
ASSERT(size <= NumberOfSignals);
std::size_t counter = 0;
for (auto tmp : Data) {
Signals.at(counter) = tmp;
counter++;
}
}
/// TODO: write description
template <typename... Types>
std::enable_if_t<std::conjunction_v<std::is_same<
Types, SystemStateInformation<CONFDATATYPE>>...>,
void>
insertSignalStateInformation(Types... Data) {
// TODO (future): think about saving the state information in a history
insertSignalStateInfos(
std::array<SystemStateInformation<CONFDATATYPE>, sizeof...(Data)>(
{Data...}));
}
// returns true if they are identical
/// TODO: write description
template <std::size_t size>
bool compareSignalStateInformation(
const std::array<SystemStateInformation<CONFDATATYPE>, size>
&Data) noexcept {
// TODO (future): think about saving the state information in a history
std::size_t counter = 0;
for (auto tmp : Data) {
if (Signals.at(counter) != tmp)
return false;
counter++;
}
return true;
}
// checks only the given amount
/// TODO: write description
template <typename... Types>
std::enable_if_t<std::conjunction_v<std::is_same<
Types, SystemStateInformation<CONFDATATYPE>>...>,
bool>
compareSignalStateInformation(Types... Data) {
return compareSignalStateInfos(
std::array<SystemStateInformation<CONFDATATYPE>, sizeof...(Data)>(
{Data...}));
}
#endif
/// Gives information about the current signal state.
///
/// \return a struct SignalStateInformation that contains information about
/// the current signal state.
SystemStateInformation<CONFDATATYPE> systemStateInformation(void) noexcept {
return SystemStateInfo;
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_SYSTEMSTATE_HPP
diff --git a/include/rosa/support/atom.hpp b/include/rosa/support/atom.hpp
index e3ea9a2..eac70f8 100644
--- a/include/rosa/support/atom.hpp
+++ b/include/rosa/support/atom.hpp
@@ -1,216 +1,216 @@
//===-- rosa/support/atom.hpp -----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/atom.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facility for *atoms*, short strings statically encoded as integers.
///
/// \note This implementation is based on the \c atom implementation of CAF.
///
/// *Atoms* can be used to turn short string literals into statically generated
/// types. The literals may consist of at most \c 10 non-special characters,
/// legal characters are \c _0-9A-Za-z and the whitespace character. Special
/// characters are turned into whitespace, which may result in different string
/// literals being encoded into the same integer value, if any of those contain
/// at least one special character.
///
/// \note The usage of special characters in the string literals used to create
/// *atoms* cannot be checked by the compiler.
///
/// Example:
///
/// \code
/// constexpr AtomValue NameValue = atom("name");
/// using NameAtom = AtomConstant<NameValue>;
///
/// [](NameAtom){ std::cout << "Argument of type NameAtom"; }(NameAtom::Value)
/// \endcode
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_ATOM_HPP
#define ROSA_SUPPORT_ATOM_HPP
#include "rosa/support/debug.hpp"
#include <string>
#include <cstring>
namespace rosa {
/// Maximal length of valid atom strings.
constexpr size_t MaxAtomLength = 10;
/// Underlying integer type of atom values.
using atom_t = uint64_t;
/// Turn \c rosa::atom_t into a strongly typed enumeration.
///
/// Values of \c rosa::atom_t casted to \c rosa::AtomValue may be used in a
/// type-safe way.
enum class AtomValue : atom_t {};
/// Anonymous namespace with implementational details, consider it private.
namespace {
// clang-format off
/// Encodes ASCII characters to 6-bit encoding.
constexpr unsigned char AtomEncodingTable[] = {
/* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */
/* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 3.. */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0,
/* 4.. */ 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
/* 5.. */ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 0, 0, 0, 0, 37,
/* 6.. */ 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
/* 7.. */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0};
// clang-format on
/// Decodes 6-bit characters to ASCII
constexpr char AtomDecodingTable[] = " 0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"abcdefghijklmnopqrstuvwxyz";
/// Encodes one character and updates the integer representation.
///
/// \param Current an encoded value
/// \param CharCode a character to add to \p Current
///
/// \return \p Current updated with \p CharCode
constexpr atom_t nextInterim(atom_t Current, size_t CharCode) {
return (Current << 6) | AtomEncodingTable[(CharCode <= 0x7F) ? CharCode : 0];
}
/// Encodes a C-string into an integer value to be used as \c rosa::AtomValue.
///
/// \param CStr a string to encode
/// \param Interim encoded value to add \p CStr to it
///
/// \return \p Interim updated with \p CStr
constexpr atom_t atomValue(const char *CStr, atom_t Interim = 0xF) {
return (*CStr == '\0')
? Interim
: atomValue(CStr + 1,
nextInterim(Interim, static_cast<size_t>(*CStr)));
}
} // End namespace
/// Converts a \c std::string into a \c rosa::AtomValue.
///
/// \param S \c std::string to convert
///
/// \return \c rosa::AtomValue representing \p S
AtomValue atom_from_string(const std::string &S);
/// Converts a string-literal into a \c rosa::AtomValue.
///
/// \tparam Size the length of \p Str
///
/// \param Str the string-literal to convert
///
/// \return \c rosa::AtomValue representating \p Str
///
/// \pre \p Str is not too long:\code
/// Size <= MaxAtomLength + 1
/// \endcode
template <size_t Size> constexpr AtomValue atom(char const (&Str)[Size]) {
// Last character is the NULL terminator.
STATIC_ASSERT(Size <= MaxAtomLength + 1,
"Too many characters in atom definition");
return static_cast<AtomValue>(atomValue(Str));
}
/// Lifts a \c rosa::AtomValue to a compile-time constant.
///
/// \tparam V \c rosa::AtomValue to lift
template <AtomValue V> struct AtomConstant {
/// Constructor has to do nothing.
- constexpr AtomConstant(void) {}
+ constexpr AtomConstant(void) = default;
/// Returns the wrapped value.
///
/// \return \p V
constexpr operator AtomValue(void) const { return V; }
/// Returns the wrapped value as of type \c rosa::atom_t.
///
/// \return \c rosa::atom_t value from \p V
static constexpr atom_t value() { return static_cast<atom_t>(V); }
/// An instance *of this constant* (*not* a \c rosa::AtomValue).
static const AtomConstant Value;
};
// Implementation of the static member field \c rosa::AtomConstant::Value.
template <AtomValue V>
const AtomConstant<V> AtomConstant<V>::Value = AtomConstant<V>{};
} // End namespace rosa
namespace std {
/// Converts a \c rosa::AtomValue into \c std::string.
///
/// \param What value to convert
///
/// \return \c std::string encoded in \p What
string to_string(const rosa::AtomValue &What);
/// Dumps a \c rosa::AtomValue to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param A \c rosa::AtomValue to dump
///
/// \return \p OS after dumping \p N to it
inline ostream &operator<<(ostream &OS, const rosa::AtomValue &A) {
OS << to_string(A);
return OS;
}
/// Converts a \c rosa::AtomConstant into \c std::string.
///
/// \tparam V \c rosa::AtomValue to convert
///
/// \note The actual argument of type `const rosa::AtomConstant<V>` is ignored
/// because the \c rosa::AtomValue to convert is encoded in the type itself.
///
/// \return the original string encoded in \p V
template <rosa::AtomValue V> string to_string(const rosa::AtomConstant<V> &) {
return to_string(V);
}
/// Dumps a \c rosa::AtomConstant to a given \c std::ostream.
///
/// \tparam V the \c rosa::AtomValue to dump
///
/// \param [in,out] OS output stream to dump to
/// \param A \c rosa::AtomConstant providing \p V
///
/// \return \p OS after dumping \p V to it
template <rosa::AtomValue V>
inline ostream &operator<<(ostream &OS, const rosa::AtomConstant<V> &A) {
(void)A; // Shut compiler about unused parameter.
OS << to_string(V);
return OS;
}
} // End namespace std
#endif // ROSA_SUPPORT_ATOM_HPP
diff --git a/include/rosa/support/tokenized_storages.hpp b/include/rosa/support/tokenized_storages.hpp
index d241de6..e3acdfc 100755
--- a/include/rosa/support/tokenized_storages.hpp
+++ b/include/rosa/support/tokenized_storages.hpp
@@ -1,629 +1,629 @@
//===-- rosa/support/tokenized_storages.hpp ---------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/tokenized_storages.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Definition of storage helper template for storing values in a
/// type-safe way based on type tokens.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
#define ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
#include "rosa/support/log.h"
#include "rosa/support/type_token.hpp"
#include <memory>
#include <vector>
namespace rosa {
/// Defines a simple interface for storing and accessing values of different
/// types.
///
/// While the interface provides features to access values and know their
/// types, it is the users responsibility to use particular values according to
/// their actual types. No facilities for type-safe access of values is
/// provided by the class.
///
/// \see \c rosa::TokenizedStorage for a type-safe specialization of the
/// interface.
class AbstractTokenizedStorage {
protected:
/// Protected constructor restricts instantiation for derived classes.
AbstractTokenizedStorage(void) noexcept = default;
public:
/// No copying and moving of \c rosa::AbstractTokenizedStorage instances.
///@{
AbstractTokenizedStorage(const AbstractTokenizedStorage &) = delete;
AbstractTokenizedStorage &
operator=(const AbstractTokenizedStorage &) = delete;
AbstractTokenizedStorage(AbstractTokenizedStorage &&Other) = delete;
AbstractTokenizedStorage &operator=(AbstractTokenizedStorage &&) = delete;
///@}
/// Destroys \p this object.
virtual ~AbstractTokenizedStorage(void) noexcept = default;
/// Tells how many values are stored in \p this object.
///
/// \return number of values stored in \p this object
virtual size_t size(void) const noexcept = 0;
/// Tells the type of the value stored at a position.
///
/// \param Pos the index of the value whose type is to returned
///
/// \return \c rosa::TypeNumber for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
virtual TypeNumber typeAt(const token_size_t Pos) const noexcept = 0;
/// Provides an untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
virtual void *pointerTo(const token_size_t Pos) noexcept = 0;
/// Provides a constant untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return constant untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < Offsets.size()
/// \endcode
virtual const void *pointerTo(const token_size_t Pos) const noexcept = 0;
};
/// Template class storing values and providing dynamic type-safe access to
/// them in a lightweight way based on type tokens.
///
/// \see rosa/support/type_token.hpp
///
/// \tparam Types types whose values are to be stored
template <typename... Types> class TokenizedStorage;
/// \defgroup TokenizedStorageForTypeList Implementation of
/// rosa::TokenizedStorageForTypeList
///
/// \brief Transforms a \c rosa::TypeList instance to the corresponding
/// \c rosa::TokenizedStorage instance.
///
/// A \c rosa::TypeList \c List instance can be turned into a corresponding \c
/// rosa::TokenizedStorage instance as \code
/// typename TokenizedStorageForTypeList<List>::Type
/// \endcode
///
/// For example, the following expression evaluates to `true`: \code
/// std::is_same<typename TokenizedStorageForTypeList<TypeList<T1, T2>>::Type,
/// TokenizedStorage<T1, T2>>::value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to transform
template <typename List> struct TokenizedStorageForTypeList;
/// Implementation of the template for \c rosa::TypeList instances.
template <typename... Ts> struct TokenizedStorageForTypeList<TypeList<Ts...>> {
using Type = TokenizedStorage<Ts...>;
};
///@}
/// Nested namespace with implementation for \c rosa::TokenizedStorage, consider
/// it private.
namespace {
/// Initializes a pre-allocated memory area with values from constant lvalue
/// references.
///
/// \tparam Types types whose values are to be stored
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts the values to store in \p Arena
///
/// \note \p Arena needs to be a valid pointer to a memory area big enough for
/// values of \p Types.
template <typename... Types>
inline void createArenaElements(void *const Arena,
const Types &... Ts) noexcept;
/// \defgroup createLvalueArenaElement Implementation of creating lvalue arena
/// elements
///
/// Stores values from constant lvalue references into a pre-allocated memory
/// area.
///
/// \note To be used by the implementation of \c createArenaElements.
///
/// \todo Document these functions.
///@{
/// \note This terminal case is used for both constant lvalue references and
/// value references.
template <size_t Pos>
inline void createArenaElement(void *const,
const std::vector<size_t> &Offsets) {
ASSERT(Pos == Offsets.size());
}
template <size_t Pos, typename Type, typename... Types>
inline void createArenaElement(void *const Arena,
const std::vector<size_t> &Offsets,
const Type &T, const Types &... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
new (static_cast<Type *>(static_cast<void *>(static_cast<uint8_t *>(Arena) +
Offsets[Pos]))) Type(T);
createArenaElement<Pos + 1>(Arena, Offsets, Ts...);
}
template <size_t Pos, AtomValue V, typename... Types>
inline void
createArenaElement(void *const Arena, const std::vector<size_t> &Offsets,
const AtomConstant<V> &, const Types &... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
*static_cast<AtomValue *>(
static_cast<void *>(static_cast<uint8_t *>(Arena) + Offsets[Pos])) = V;
createArenaElement<Pos + 1>(Arena, Offsets, Ts...);
}
///@}
/// Implementation of the template.
///
/// \tparam Types types of values to store
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts values to store in \p Arena
///
/// \pre \p Arena is not \p nullptr.
template <typename... Types>
inline void createArenaElements(void *const Arena,
const Types &... Ts) noexcept {
ASSERT(Arena != nullptr);
createArenaElement<0>(Arena, TokenizedStorage<Types...>::Offsets, Ts...);
}
/// Initializes a pre-allocated memory area with values from rvalue references.
///
/// \tparam Types types whose values are to be stored
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts the values to store in \p Arena
///
/// \note \p Arena needs to be a valid pointer to a memory area big enough for
/// values of \p Types.
template <typename... Types>
inline void createArenaElements(void *const Arena, Types &&... Ts) noexcept;
/// \defgroup createRvalueArenaElement Implementation of creating rvalue arena
/// elements
///
/// Stores values from rvalue references into a pre-allocated memory area.
///
/// \note To be used by the implementation of \c createArenaElements.
///
/// \todo Document these functions.
///@{
template <size_t Pos, typename Type, typename... Types>
inline void createArenaElement(void *const Arena,
const std::vector<size_t> &Offsets, Type &&T,
Types &&... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
new (static_cast<Type *>(static_cast<void *>(
static_cast<uint8_t *>(Arena) + Offsets[Pos]))) Type(std::move(T));
createArenaElement<Pos + 1>(Arena, Offsets, std::move(Ts)...);
}
template <size_t Pos, AtomValue V, typename... Types>
inline void createArenaElement(void *const Arena,
const std::vector<size_t> &Offsets,
AtomConstant<V> &&, Types &&... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
*static_cast<AtomValue *>(
static_cast<void *>(static_cast<uint8_t *>(Arena) + Offsets[Pos])) = V;
createArenaElement<Pos + 1>(Arena, Offsets, std::move(Ts)...);
}
///@}
/// Implementation of the template.
///
/// \tparam Types types of values to store
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts values to store in \p Arena
///
/// \pre \p Arena is not \c nullptr.
template <typename... Types>
inline void createArenaElements(void *const Arena, Types &&... Ts) noexcept {
ASSERT(Arena != nullptr);
createArenaElement<0>(Arena, TokenizedStorage<Types...>::Offsets,
std::move(Ts)...);
}
/// Destroys values allocated by \c createArenaElements.
///
/// \tparam Types types whose values are stored in \p Arena
///
/// \param Arena the memory area to destroy values from
///
/// \note \p Arena needs to be a valid pointer to a memory area where values of
/// \p Types are stored.
template <typename... Types>
inline void destroyArenaElements(void *const Arena) noexcept;
/// \defgroup destroyArenaElement Implementation of destroying arena elements
///
/// Destroys values from a memory area.
///
/// \note To be used by the implementation of \c destroyArenaElements.
///
/// \todo Document these functions.
///@{
template <size_t Pos>
inline void destroyArenaElement(void *const,
const std::vector<size_t> &Offsets) noexcept {
ASSERT(Pos == Offsets.size());
}
template <size_t Pos, typename Type, typename... Types>
inline void destroyArenaElement(void *const Arena,
const std::vector<size_t> &Offsets) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
static_cast<Type *>(
static_cast<void *>(static_cast<uint8_t *>(Arena) + Offsets[Pos]))
->~Type();
destroyArenaElement<Pos + 1, Types...>(Arena, Offsets);
}
///@}
/// Implementation of the template.
///
/// \tparam Types types of values to destroy
///
/// \param Arena the memory area to destroy values from
///
/// \pre \p Arena is not \c nullptr.
template <typename... Types>
inline void destroyArenaElements(void *const Arena) noexcept {
ASSERT(Arena != nullptr);
destroyArenaElement<0, Types...>(Arena, TokenizedStorage<Types...>::Offsets);
}
} // End namespace
/// Implementation of the template \c rosa::TokenizedStorage as a
/// specialization of \c rosa::AbstractTokenizedStorage.
///
/// The class provides facilities for storing values and providing type-safe
/// access to them.
///
/// \tparam Types types of values to store
template <typename... Types>
class TokenizedStorage : public AbstractTokenizedStorage {
public:
/// \c rosa::Token for the stored values.
static constexpr Token ST = TypeToken<std::decay_t<Types>...>::Value;
/// Byte offsets to access stored values in \c rosa::TokenizedStorage::Arena.
static const std::vector<size_t> Offsets;
private:
/// A BLOB storing all the values one after the other.
void *const Arena;
/// Generates byte offsets for accessing values stored in
/// \c rosa::TokenizedStorage::Arena.
///
/// \return \c std::vector containing byte offsets for accessing values stored
/// in \c rosa::TokenizedStorage::Arena
static std::vector<size_t> offsets(void) noexcept {
Token T = ST; // Need a mutable copy.
const token_size_t N = lengthOfToken(T); // Number of types encoded in \c T.
std::vector<size_t> O(N); // Allocate vector of proper size.
// Do nothing for 0 elements.
if (N > 0) {
token_size_t I = 0; // Start indexing from position \c 0.
O[0] = 0; // First offset is always \c 0.
while (I < N - 1) {
ASSERT(I + 1 < O.size() && lengthOfToken(T) == N - I);
// Calculate next offset based on the previous one.
// \note The offset of the last value is stored at `O[N - 1]`, which is
// set when `I == N - 2`. Hence the limit of the loop.
O[I + 1] = O[I] + sizeOfHeadOfToken(T);
dropHeadOfToken(T);
++I;
}
ASSERT(I + 1 == O.size() && lengthOfToken(T) == 1);
}
return O;
}
public:
/// Creates an instance with default values.
///
/// \note This constructor requires that all actual template arguments \p
/// Types... are default constructible.
TokenizedStorage(void) noexcept
: Arena(::operator new(sizeOfValuesOfToken(ST))) {
ASSERT(Arena != nullptr); // Sanity check.
createArenaElements(Arena, Types()...);
}
/// Creates an instance from constant lvalue references.
///
/// \param Ts values to store
TokenizedStorage(const std::decay_t<Types> &... Ts) noexcept
: Arena(::operator new(sizeOfValuesOfToken(ST))) {
ASSERT(Arena != nullptr); // Sanity check.
createArenaElements(Arena, Ts...);
}
/// Creates an instance from rvalue references.
///
/// \param Ts values to store
TokenizedStorage(std::decay_t<Types> &&... Ts) noexcept
: Arena(::operator new(sizeOfValuesOfToken(ST))) {
ASSERT(Arena != nullptr); // Sanity check.
createArenaElements(Arena, std::move(Ts)...);
}
/// No copying and moving of \c rosa::TokenizedStorage instances.
///
/// \note This restriction may be relaxed as moving should be easy to
/// implement, only requires the possiblity to validate Arena pointer.
///@{
TokenizedStorage(const TokenizedStorage &) = delete;
TokenizedStorage &operator=(const TokenizedStorage &) = delete;
TokenizedStorage(TokenizedStorage &&Other) = delete;
TokenizedStorage &operator=(TokenizedStorage &&) = delete;
///@}
// Destroys \p this object.
~TokenizedStorage(void) {
destroyArenaElements<std::decay_t<Types>...>(Arena);
::operator delete(Arena);
}
/// Tells how many values are stored in \p this object.
///
/// \return number of values stored in \p this object
size_t size(void) const noexcept override { return Offsets.size(); }
/// Tells the type of the value stored at a position.
///
/// \param Pos the index of the value whose type is to returned
///
/// \return \c rosa::TypeNumber for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
TypeNumber typeAt(const token_size_t Pos) const noexcept override {
ASSERT(Pos < size());
Token TT = ST;
dropNOfToken(TT, Pos);
return headOfToken(TT);
}
/// Provides an untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
void *pointerTo(const token_size_t Pos) noexcept override {
ASSERT(Pos < size());
return static_cast<uint8_t *>(Arena) + Offsets[Pos];
}
/// Provides a constant untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return constant untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < Offsets.size()
/// \endcode
const void *pointerTo(const token_size_t Pos) const noexcept override {
ASSERT(Pos < size());
return static_cast<const uint8_t *>(Arena) + Offsets[Pos];
}
/// Tells if the value stored at a given index is of a given type.
///
/// \note Any \c rosa::AtomConstant is encoded in \c rosa::Token as
/// the \c rosa::AtomValue wrapped into it.
///
/// \tparam T type to match against
///
/// \param Pos index the type of the value at is to be matched against \p Type
///
/// \return if the value at index \p Pos of type \p T
///
/// \pre \p Pos is a valid index:\code
/// Pos < Offsets.size()
/// \endcode
template <typename T> bool isTypeAt(const size_t Pos) const noexcept {
ASSERT(Pos < size());
Token TT = ST;
dropNOfToken(TT, Pos);
return isHeadOfTokenTheSameType<T>(TT);
}
/// Gives a reference of a value of a given type stored at a given index.
///
/// \note The constant variant of the function relies on this implementation,
/// the function may not modify \p this object!
///
/// \tparam T type to give a reference of
///
/// \param Pos index to set the reference for
///
/// \return reference of \p T for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index and the value at index \p Pos is of type
/// \p T:
/// \code
/// Pos < Size && isTypeAt<T>(Pos)
/// \endcode
template <typename T> T &valueAt(const token_size_t Pos) noexcept {
ASSERT(Pos < size() && isTypeAt<T>(Pos));
return *static_cast<T *>(pointerTo(Pos));
}
/// Gives a constant reference of a value of a given type stored at a given
/// index.
///
/// \tparam T type to give a reference of
///
/// \param Pos index to set the reference for
///
/// \return constant reference of \p T for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index and the value at index \p Pos is of type
/// \p T:
/// \code
/// Pos < Size && isTypeAt<T>(Pos)
/// \endcode
template <typename T>
const T &valueAt(const token_size_t Pos) const noexcept {
// \note Just use the non-const implementation as that does not modify
// \p this object.
return const_cast<TokenizedStorage *>(this)->valueAt<T>(Pos);
}
};
// Implementation of the static member field \c rosa::TokenizedStorage::Offsets.
template <typename... Types>
const std::vector<size_t>
TokenizedStorage<Types...>::Offsets = TokenizedStorage<Types...>::offsets();
/// Specialization of the template \c rosa::TokenizedStorage for storing
/// nothing.
///
/// \note The specialization implements the interface defined by \c
/// rosa::AbstractTokenizedStorage but most of the functions cannot be called
/// because nothing is stored in instances of the class.
template <> class TokenizedStorage<> : public AbstractTokenizedStorage {
public:
/// \c rosa::Token for the stored values.
static constexpr Token ST = TypeToken<>::Value;
/// Byte offsets to access stored values in \c rosa::TokenizedStorage::Arena.
static const std::vector<size_t> Offsets;
/// Creates an instance.
- TokenizedStorage(void) noexcept {}
+ TokenizedStorage(void) noexcept = default;
/// No copying and moving of \c rosa::TokenizedStorage instances.
///
/// \note This restriction may be relaxed as moving should be easy to
/// implement, only requires the possiblity to validate Arena pointer.
///@{
TokenizedStorage(const TokenizedStorage &) = delete;
TokenizedStorage &operator=(const TokenizedStorage &) = delete;
TokenizedStorage(TokenizedStorage &&Other) = delete;
TokenizedStorage &operator=(TokenizedStorage &&) = delete;
///@}
// Destroys \p this object.
~TokenizedStorage(void) override {}
/// Tells how many values are stored in \p this object.
///
/// \return `0`
size_t size(void) const noexcept override { return 0; }
/// Tells the type of the value stored at a position.
///
/// \pre Do not call.
TypeNumber typeAt(const token_size_t) const noexcept override {
LOG_ERROR("Called unsupported function");
return TypeNumber(0);
}
/// Provides an untyped pointer for the value stored at a position.
///
/// \pre Do not call.
void *pointerTo(const token_size_t) noexcept override {
LOG_ERROR("Called unsupported function");
return nullptr;
}
/// Provides a constant untyped pointer for the value stored at a position.
///
/// \pre Do not call.
const void *pointerTo(const token_size_t) const noexcept override {
LOG_ERROR("Called unsupported function");
return nullptr;
}
/// Tells if the value stored at a given index is of a given type.
///
/// \pre Do not call.
template <typename> bool isTypeAt(const size_t) const noexcept {
LOG_ERROR("Called unsupported function");
return false;
}
/// Gives a reference of a value of a given type stored at a given index.
///
/// \tparam T type to give a reference of
/// \pre Do not call.
template <typename T> T &valueAt(const token_size_t) noexcept {
LOG_ERROR("Called unsupported function");
return *static_cast<T *>(nullptr);
}
/// Gives a constant reference of a value of a given type stored at a given
/// index.
///
/// \tparam T type to give a reference of
///
/// \pre Do not call.
template <typename T> const T &valueAt(const token_size_t) const noexcept {
LOG_ERROR("Called unsupported function");
// \note Just use the non-const implementation as that does not modify
// \p this object.
return *static_cast<T *>(nullptr);
}
};
} // End namespace rosa
#endif // ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
diff --git a/include/rosa/support/type_list.hpp b/include/rosa/support/type_list.hpp
index ad06837..81a30cb 100644
--- a/include/rosa/support/type_list.hpp
+++ b/include/rosa/support/type_list.hpp
@@ -1,473 +1,473 @@
//===-- rosa/support/type_list.hpp ------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/type_list.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facilities for types representing lists of types.
///
/// \note This implementation is partially based on the \c type_list
/// implementation of CAF.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TYPE_LIST_HPP
#define ROSA_SUPPORT_TYPE_LIST_HPP
#include "rosa/support/debug.hpp"
#include "rosa/support/types.hpp"
#include <type_traits>
namespace rosa {
/// A list of types.
///
/// \tparam Ts types to make a list of
template <typename... Ts> struct TypeList {
/// Constructor, needs to do nothing.
- constexpr TypeList(void) {}
+ constexpr TypeList(void) = default;
};
/// The empty \c rosa::Typelist.
using EmptyTypeList = TypeList<>;
/// \defgroup TypeListAtImpl Implementation of rosa::TypeListAt
///
/// \brief Gets the type at index \p Pos from a list of types.
///
/// \note Only to be used by the implementation of \c rosa::TypeListAt.
///@{
/// Declaration of the template.
///
/// \tparam Pos index to take the element from
/// \tparam Ts types
template <size_t Pos, typename... Ts> struct TypeListAtImpl;
/// Definition for the general case when \p Pos is not \c 0 and there is type in
/// the list.
template <size_t Pos, typename T, typename... Ts>
struct TypeListAtImpl<Pos, T, Ts...> {
using Type = typename TypeListAtImpl<Pos - 1, Ts...>::Type;
};
/// Specialization for the case when \p Pos is \c 0.
template <typename T, typename... Ts> struct TypeListAtImpl<0, T, Ts...> {
using Type = T;
};
/// Specialization for the case when there is no more type.
///
/// In this case, the found type is \c rosa::none_t.
template <size_t Pos> struct TypeListAtImpl<Pos> { using Type = none_t; };
///@}
/// \defgroup TypeListAt Definition of rosa::TypeListAt
///
/// \brief Gets the element at index \p Pos of \p List.
///
///
/// The type at index \c Pos in a \c rosa::TypeList \c List can be obtained as
/// \code
/// typename TypeListAt<List, Pos>::Type
/// \endcode
///
/// \note The resulting type is \c rosa::none_t if \code
/// TypeListSize<List>::Value < Pos
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to take an element from
/// \tparam Pos index to take the element from
template <typename List, size_t Pos> struct TypeListAt;
/// Implementation using \c rosa::TypeListAtImpl.
template <size_t Pos, typename... Ts> struct TypeListAt<TypeList<Ts...>, Pos> {
using Type = typename TypeListAtImpl<Pos, Ts...>::Type;
};
///@}
/// \defgroup TypeListIndexOfImpl Implementation of rosa::TypeListIndexOf
///
/// \brief Tells the index of the first occurence of a type in a list of types.
///
/// \note Only to be used by the implementation of \c rosa::TypeListIndexOf.
///@{
/// Declaration of the template.
///
/// \tparam Pos the number types already being checked from the beginning of the
/// list
/// \tparam X type to search for
/// \tparam Ts remaining list of types
template <size_t Pos, typename X, typename... Ts> struct TypeListIndexOfImpl;
/// Specialization for the case when the list is over.
///
/// In this case, the found index is \c -1.
template <size_t Pos, typename X> struct TypeListIndexOfImpl<Pos, X> {
static constexpr int Value = -1;
};
/// Specialization for the case when the first type in the remaining list
/// is a match.
template <size_t Pos, typename X, typename... Ts>
struct TypeListIndexOfImpl<Pos, X, X, Ts...> {
static constexpr int Value = Pos;
};
/// Implementation for the general case when need to continue looking.
template <size_t Pos, typename X, typename T, typename... Ts>
struct TypeListIndexOfImpl<Pos, X, T, Ts...> {
static constexpr int Value = TypeListIndexOfImpl<Pos + 1, X, Ts...>::Value;
};
///@}
/// \defgroup TypeListIndexOf Definition of rosa::TypeListIndexOf
///
/// \brief Tells the index of the first occurence of type in a
/// \c rosa::TypeList.
///
/// The index of the first occurence of type \c T in \c rosa::TypeList \c List
/// can be obtained as \code
/// TypeListIndexOf<List, T>::Value
/// \endcode
///
/// \note The resulting index is \c -1 if \c T is not present in \c List.
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to search in
/// \tparam T type to search for
template <typename List, typename T> struct TypeListIndexOf;
/// Implementation of the template using \c rosa::TypeListIndexOfImpl.
template <typename... Ts, typename T>
struct TypeListIndexOf<TypeList<Ts...>, T> {
static constexpr int Value = TypeListIndexOfImpl<0, T, Ts...>::Value;
};
///@}
/// \defgroup TypeListHead Implementation of rosa::TypeListHead
///
/// \brief Gets the first element of a \c rosa::TypeList.
///
/// The first element of a \c rosa::TypeList \c List can be obtained as \code
/// typename TypeListHead<List>::Type
/// \endcode
///
/// \note The resulting type is \c rosa::none_t if \c List is
/// \c rosa::EmptyTypeList.
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to get the first element of
template <typename List> struct TypeListHead;
/// Specialization for \c rosa::EmptyTypeList.
///
/// In this case, the found type is \c rosa::none_t.
template <> struct TypeListHead<EmptyTypeList> { using Type = none_t; };
/// Implementation for a non-empty \c rosa::TypeList.
template <typename T, typename... Ts> struct TypeListHead<TypeList<T, Ts...>> {
using Type = T;
};
///@}
/// \defgroup TypeListTail Implementation of rosa::TypeListTail
///
/// \brief Gets the tail of a \c rosa::TypeList.
///
/// The tail of a \c rosa::TypeList \c List, that is \c List except for its
/// first element, can be obtained as \code
/// typename TypeListTail<List>::Type
/// \endcode
///
/// \note If \c List is \c rosa::EmptyTypeList, then the resulting type is also
/// \c rosa::EmptyTypeList.
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to take the tail of
template <typename List> struct TypeListTail;
/// Specialization for \c rosa::EmptyTypeList.
///
/// In this case, the resulting type is \c rosa::EmptyTypeList.
template <> struct TypeListTail<EmptyTypeList> { using Type = EmptyTypeList; };
/// Implementation for a non-empty \c rosa::TypeList.
template <typename T, typename... Ts> struct TypeListTail<TypeList<T, Ts...>> {
using Type = TypeList<Ts...>;
};
///@}
/// \defgroup TypeListPush Implementation of rosa::TypeListPush
///
/// \brief Extends a \c rosa::TypeList with a type.
///
/// Whether the new type is pushed in the front or in the back of the
/// \c rosa::TypeList depends on the order of template arguments, as shown in
/// the following example: \code
/// using List = TypeList<A>
/// typename TypeListPush<List, T>::Type; // TypeList<A, T>
/// typename TypeListPush<T, List>::Type; // TypeList<T, A>
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam P a type if \p Q is a \c rosa::TypeList, a \c rosa::TypeList
/// otherwise
/// \tparam Q a type if \p P is a \c rosa::TypeList, a \c rosa::TypeList
/// otherwise
template <typename P, typename Q> struct TypeListPush;
/// Implementation for the case when pushing at the back of the
/// \c rosa::TypeList.
template <typename... Ts, typename T> struct TypeListPush<TypeList<Ts...>, T> {
using Type = TypeList<Ts..., T>;
};
/// Implementation for the case when pushing to the front of the
/// \c rosa::TypeList.
template <typename T, typename... Ts> struct TypeListPush<T, TypeList<Ts...>> {
using Type = TypeList<T, Ts...>;
};
///@}
/// \defgroup TypeListDrop Implementation of rosa::TypeListDrop
///
/// \brief Drops some elements from the beginning of a \c rosa::TypeList.
///
/// The first \c N types of a \c rosa::TypeList \c List can be dropped as \code
/// typename TypeListDrop<N, List>::Type
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam N number of types to drop
/// \tparam List \c rosa::TypeList to drop the first \p N element of
template <size_t N, typename List> struct TypeListDrop;
/// Specialization for \c rosa::EmptyTypeList.
template <size_t N> struct TypeListDrop<N, EmptyTypeList> {
using Type = EmptyTypeList;
};
/// Implementation for a non-empty \c rosa::TypeList.
template <size_t N, typename T, typename... Ts>
struct TypeListDrop<N, TypeList<T, Ts...>> {
using Type = typename std::conditional<
N == 0, TypeList<T, Ts...>,
typename TypeListDrop<N - 1, TypeList<Ts...>>::Type>::type;
};
///@}
/// \defgroup TypeListConcat Implementation of rosa::TypeListConcat
///
/// \brief Concatenates two \c rosa::TypeList instances.
///
/// Two instances of \c rosa::TypeList \c List1 and \c List2 can be
/// concatenated as \code
/// typename TypeListConcat<List1, List2>::Type
/// \endcode
///@{
/// Declaration of the template
///
/// \tparam List1 the first instance of \c rosa::TypeList
/// \tparam List2 the second instance of \c rosa::TypeList
template <typename List1, typename List2> struct TypeListConcat;
/// Implementation of the template for \c rosa::TypeList instances.
template <typename... As, typename... Bs>
struct TypeListConcat<TypeList<As...>, TypeList<Bs...>> {
using Type = TypeList<As..., Bs...>;
};
///@}
/// \defgroup TypeListSize Implementation of rosa::TypeListSize
///
/// \brief Tells the number of types stored in a \c rosa::TypeList.
///
/// The size of a \c rosa::TypeList \c List can be obtained as \code
/// TypeListSize<List>::Value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to get the size of
template <typename List> struct TypeListSize;
/// Implementation of the template.
template <typename... Ts> struct TypeListSize<TypeList<Ts...>> {
static constexpr size_t Value = sizeof...(Ts);
};
template <typename... Ts> constexpr size_t TypeListSize<TypeList<Ts...>>::Value;
///@}
/// Tests whether a \c rosa::TypeList is empty.
///
/// \tparam List \c rosa::TypeList to check
template <typename List> struct TypeListEmpty {
/// Denotes whether \p List is an empty \c rosa::TypeList or not.
static constexpr bool Value = std::is_same<EmptyTypeList, List>::value;
};
/// \defgroup TypeListContains Implementation of rosa::TypeListContains
///
/// \brief Tells if a \c rosa::TypeList contains a given type.
///
/// Whether a \c rosa::TypeList \c List contains the type \c T can be checked as
/// \code
/// TypeListContains<List, T>::Value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to search in
/// \tparam T type to search for
template <typename List, typename T> struct TypeListContains;
/// Implementation of the template.
template <typename... Ts, typename T>
struct TypeListContains<TypeList<Ts...>, T> {
static constexpr bool Value =
std::conditional<TypeListIndexOf<TypeList<Ts...>, T>::Value == -1,
std::false_type, std::true_type>::type::value;
};
///@}
/// \defgroup TypeListSubsetOf Implementation of rosa::TypeListSubsetOf
///
/// \brief Tells if a \c rosa::TypeList is a subset of another one.
///
/// Whether a \c rosa::TypeList \c ListA is a subset of another
/// \c rosa::TypeList \c ListB can be checked as \code
/// TypeListSubsetOf<ListA, ListB>::Value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam ListA \c rosa::TypeList to check if is a subset of \p ListB
/// \tparam ListB \c rosa::TypeList to check if is a superset of \p ListA
/// \tparam Fwd always use the default value!
template <typename ListA, typename ListB, bool Fwd = true>
struct TypeListSubsetOf;
/// Specialization for the case when all the elements of the original \p ListA
/// was found in \p ListB.
template <typename List> struct TypeListSubsetOf<EmptyTypeList, List, true> {
static constexpr bool Value = true;
};
/// Specializaton for the case when an element of the original \p ListA cannot
/// be found in \p ListB.
template <typename ListA, typename ListB>
struct TypeListSubsetOf<ListA, ListB, false> {
static constexpr bool Value = false;
};
/// Definition for the general case.
template <typename T, typename... Ts, typename List>
struct TypeListSubsetOf<TypeList<T, Ts...>, List>
: TypeListSubsetOf<TypeList<Ts...>, List,
TypeListContains<List, T>::Value> {};
///@}
/// \defgroup TypeListFindImpl Implementation of rosa::TypeListFind
///
/// \brief Finds the first type in a list of types that satisfies a predicate.
///
/// \note Only to be used by the implementation of \c rosa::TypeListFind.
///@{
/// Declaration of the template.
///
/// \tparam Pred the predicate to check types against
/// \tparam Ts list of types to check
template <template <typename> class Pred, typename... Ts>
struct TypeListFindImpl;
/// Specialization for the case when no more types remain to check.
template <template <typename> class Pred> struct TypeListFindImpl<Pred> {
using Type = none_t;
};
/// Implementation for the general case when there is a type to check.
template <template <typename> class Pred, typename T, typename... Ts>
struct TypeListFindImpl<Pred, T, Ts...> {
using Type = typename std::conditional<
Pred<T>::Value, T, typename TypeListFindImpl<Pred, Ts...>::Type>::type;
};
///@}
/// \defgroup TypeListFind Definition of rosa::TypeListFind
///
/// \brief Finds the first element satisfying a predicate in a
/// \c rosa::TypeList.
///
/// The first type satisfying a predicate \c Pred in a \c rosa::TypeList
/// \c List can be obtained as \code
/// typename TypeListFind<List, Pred>::Type
/// \endcode
///
/// \note The resulting type is \c rosa::none_t if no type in \c List satisfies
/// \c Pred.
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to search in
/// \tparam Pred predicate to check elements against
template <typename List, template <typename> class Pred> struct TypeListFind;
/// Implementation of the template using \c rosa::TypeListFindImpl.
template <typename... Ts, template <typename> class Pred>
struct TypeListFind<TypeList<Ts...>, Pred> {
using Type = typename TypeListFindImpl<Pred, Ts...>::Type;
};
///@}
} // End namespace rosa
#endif // ROSA_SUPPORT_TYPE_LIST_HPP
diff --git a/include/rosa/support/types.hpp b/include/rosa/support/types.hpp
index afeb508..74c22f3 100644
--- a/include/rosa/support/types.hpp
+++ b/include/rosa/support/types.hpp
@@ -1,555 +1,555 @@
//===-- rosa/support/types.hpp ----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/types.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Implementation of some basic convenience types.
///
/// \note This implementation is partially based on the implementation of
/// corresponding parts of CAF.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TYPES_HPP
#define ROSA_SUPPORT_TYPES_HPP
#include "rosa/support/debug.hpp"
#include <string>
namespace rosa {
/* ************************************************************************** *
* Unit *
* ************************************************************************** */
/// A safe type to replace \c void.
///
/// \c rosa::UnitType is analogous to \c void, but can be safely returned,
/// stored, etc. to enable higher-order abstraction without cluttering code with
/// exceptions for \c void (which can't be stored, for example).
struct UnitType {
/// Constructor, needs to do nothing.
- constexpr UnitType() noexcept {}
+ constexpr UnitType() noexcept = default;
/// Copy-constructor, needs to do nothing.
- constexpr UnitType(const UnitType &) noexcept {}
+ constexpr UnitType(const UnitType &) noexcept = default;
};
/// Aliasing \c rosa::UnitType as \c rosa::unit_t.
using unit_t = UnitType;
/// The value of \c rosa::unit_t.
///
/// \note Since a value of \c rosa::UnitType has no state, all instances of
/// \c rosa::UnitType is equal and considered *the \c rosa::unit_t value*.
static constexpr unit_t unit = unit_t{}; // NOLINT
/// \name LiftVoid
/// \brief Lifts a type to avoid \c void.
///
/// A type \c T can be lifted as \code
/// typename LiftVoid<T>::Type
/// \endcode
/// The resulted type is \c rosa::unit_t if \c T is \c void, and \c T itself
/// otherwise.
///@{
/// Definition for the general case.
///
/// \tparam T type to lift
template <typename T> struct LiftVoid { using Type = T; };
/// Specialization for \c void.
template <> struct LiftVoid<void> { using Type = unit_t; };
///@}
/// \name UnliftVoid
/// \brief Unlifts a type already lifted by \c rosa::LiftVoid.
///
/// A type \c T can be unlifted as \code
/// typename UnliftVoid<T>::Type
/// \endcode
/// The resulted type is \c void if \c T is \c rosa::unit_t -- that is \c void
/// lifted by \c rosa::LiftVoid --, and \c T itself otherwise.
///
///@{
/// Definition for the general case.
///
/// \tparam T type to unlift
template <typename T> struct UnliftVoid { using Type = T; };
/// Specialization for \c rosa::unit_t.
template <> struct UnliftVoid<unit_t> { using Type = void; };
///@}
/* ************************************************************************** *
* None *
* ************************************************************************** */
/// Represents *nothing*.
///
/// An instance of the type represents *nothing*, that can be used, e.g., for
/// clearing an instance of \c rosa::Optional by assigning an instance of
/// \c rosa::NoneType to it.
struct NoneType {
/// Constructor, needs to do nothing.
- constexpr NoneType(void) {}
+ constexpr NoneType(void) = default;
/// Evaluates the instance to \c bool.
///
/// A "nothing" is always evaluates to \c false.
constexpr explicit operator bool(void) const { return false; }
};
/// Aliasing type \c rosa::NoneType as \c rosa::none_t.
using none_t = NoneType;
/// The value of \c rosa::none_t.
///
/// \note Since a value of \c rosa::NoneType has no state, all instances of
/// \c rosa::NoneType is equal and considered *the \c rosa::none_t value*.
static constexpr none_t none = none_t{}; // NOLINT
/* ************************************************************************** *
* Optional *
* ************************************************************************** */
/// \defgroup Optional Specializations of rosa::Optional
///
/// \brief Represents an optional value.
///
/// \note This implementation is compatible with \c std::optional of C++17.
///@{
/// Definition for the general case, optionally storing a value.
///
/// \tparam T type of the optional value
template <class T> class Optional {
public:
using Type = T;
/// Creates an instance without value.
///
/// \note Use it with its default parameter.
Optional(const none_t & = none) : Valid(false) {}
/// Creates a valid instance with value.
///
/// \tparam U type of the \p X
/// \tparam E always use it with default value!
///
/// \param X value to store in the object
///
/// \note The constructor is available for types that are convertible to \p T.
template <class U, class E = typename std::enable_if<
std::is_convertible<U, T>::value>::type>
Optional(U X) : Valid(false) {
cr(std::move(X));
}
/// Creates an instance as a copy of another one.
///
/// \param Other the instance whose state to copy
Optional(const Optional &Other) : Valid(false) {
if (Other.Valid) {
cr(Other.Value);
}
}
/// Creates an instance by moving the state of another one.
///
/// \param Other the instance whose state to obtain
Optional(Optional &&Other) noexcept(
std::is_nothrow_move_constructible<T>::value)
: Valid(false) {
if (Other.Valid) {
cr(std::move(Other.Value));
}
}
/// Destroys \p this object.
~Optional(void) { destroy(); }
/// Updates \p this object by copying the state of another one.
///
/// \param Other the instance whose state to copy
///
/// \return reference of the updated instance
Optional &operator=(const Optional &Other) {
if (Valid) {
if (Other.Valid) {
Value = Other.Value;
} else {
destroy();
}
} else if (Other.Valid) {
cr(Other.Value);
}
return *this;
}
/// Updates \p this object by moving the state of another one.
///
/// \param Other the instance whose state to obtain
///
/// \return reference of the updated instance
Optional &operator=(Optional &&Other) noexcept(
std::is_nothrow_destructible<T>::value
&&std::is_nothrow_move_assignable<T>::value) {
if (Valid) {
if (Other.Valid) {
Value = std::move(Other.Value);
} else {
destroy();
}
} else if (Other.Valid) {
cr(std::move(Other.Value));
}
return *this;
}
/// Checks whether \p this object contains a value.
///
/// \return if \p this object contains a value
explicit operator bool(void) const { return Valid; }
/// Checks whether \p this object does not contain a value.
///
/// \return if \p this object does not contain a value
bool operator!(void)const { return !Valid; }
/// Returns the value stored in \p this object.
///
/// \return reference of the stored value
///
/// \pre \p this object contains a value
T &operator*(void) {
ASSERT(Valid);
return Value;
}
/// Returns the value stored in \p this object.
///
/// \return reference of the stored value
///
/// \pre \p this object contains a value
const T &operator*(void)const {
ASSERT(Valid);
return Value;
}
/// Returns the value stored in \p this object.
///
/// \return pointer to the stored value
///
/// \pre \p this object contains a value
const T *operator->(void)const {
ASSERT(Valid);
return &Value;
}
/// Returns the value stored in \p this object.
///
/// \return pointer of the stored value
///
/// \pre \p this object contains a value
T *operator->(void) {
ASSERT(Valid);
return &Value;
}
/// Returns the value stored in \p this object.
///
/// \return reference of the stored value
///
/// \pre \p this object contains a value
T &value(void) {
ASSERT(Valid);
return Value;
}
/// Returns the value stored in \p this object.
///
/// \return reference of the stored value
///
/// \pre \p this object contains a value
const T &value(void) const {
ASSERT(Valid);
return Value;
}
/// Returns the stored value or a default.
///
/// If \p this object contains a value, then the stored value is returned. A
/// given default value is returned otherwise.
///
/// \param DefaultValue the value to return if \p this object does not contain
/// a value
///
/// \return reference to either the stored value or \p DefaultValue if \p this
/// object does not contain a value
const T &valueOr(const T &DefaultValue) const {
return Valid ? Value : DefaultValue;
}
private:
/// Deallocates the stored value if any.
void destroy(void) {
if (Valid) {
Value.~T();
Valid = false;
}
}
/// Updates the state of \p this object by moving a value into it.
///
/// \tparam V type of \p X
///
/// \param X value to move
///
/// \pre \p this object does not contain a value
template <class V> void cr(V &&X) {
ASSERT(!Valid);
Valid = true;
new (&Value) T(std::forward<V>(X));
}
/// Denotes if \p this object contains a value.
bool Valid;
/// Holds the stored value if any.
union {
T Value; ///< The stored value.
};
};
/// Specialization storing a reference.
///
/// The specialization allows \p rosa::Optional to hold a reference
/// rather than an actual value with minimal overhead.
///
/// \tparam T the base type whose reference is to be stored
template <typename T> class Optional<T &> {
public:
using Type = T;
/// Creates an instance without reference
///
/// \note Use it with its default parameter.
Optional(const none_t & = none) : Value(nullptr) {}
/// Creates a valid instance with reference.
///
/// \param X reference to store in the object
Optional(T &X) : Value(&X) {}
/// Creates a valid instance with reference.
///
/// \param X pointer to store in the object as reference
Optional(T *X) : Value(X) {}
/// Creates an instance as a copy of another one.
///
/// \param Other the instance whose state to copy
Optional(const Optional &Other) = default;
/// Updates \p this object by copying the state of another one.
///
/// \param Other the instance whose state to copy
///
/// \return reference of the updated instance
Optional &operator=(const Optional &Other) = default;
/// Checks whether \p this object contains a reference.
///
/// \return if \p this object contains a reference
explicit operator bool(void) const { return Value != nullptr; }
/// Checks whether \p this object does not contain a reference.
///
/// \return if \p this object does not contain a reference
bool operator!(void)const { return !Value; }
/// Returns the reference stored in \p this object.
///
/// \return the stored reference
///
/// \pre \p this object contains a reference
T &operator*(void) {
ASSERT(Value);
return *Value;
}
/// Returns the value stored in \p this object.
///
/// \return the stored reference
///
/// \pre \p this object contains a reference
const T &operator*(void)const {
ASSERT(Value);
return *Value;
}
/// Returns the value stored in \p this object.
///
/// \return the stored reference
///
/// \pre \p this object contains a reference
T *operator->(void) {
ASSERT(Value);
return Value;
}
/// Returns the value stored in \p this object.
///
/// \return the stored reference
///
/// \pre \p this object contains a reference
const T *operator->(void)const {
ASSERT(Value);
return Value;
}
/// Returns the value stored in \p this object.
///
/// \return the stored reference
///
/// \pre \p this object contains a reference
T &value(void) {
ASSERT(Value);
return *Value;
}
/// Returns the value stored in \p this object.
///
/// \return the stored reference
///
/// \pre \p this object contains a reference
const T &value(void) const {
ASSERT(Value);
return *Value;
}
/// Returns the stored reference or a default.
///
/// If \p this object contains a reference, then the stored reference is
/// returned. A given default value is returned otherwise.
///
/// \param DefaultValue the value to return if \p this object does not contain
/// a reference
///
/// \return either the stored reference or \p DefaultValue if \p this object
/// does not contain a reference
const T &valueOr(const T &DefaultValue) const {
return Value ? Value : DefaultValue;
}
private:
/// The stored reference as a pointer.
T *Value;
};
/// Specialization storing \c void.
///
/// The specialization allows \c rosa::Optional to implement a flag for \c void.
template <> class Optional<void> {
public:
using Type = unit_t;
/// Creates an instance with a \c false flag.
///
/// \note Use it with its default parameter.
Optional(none_t = none) : Value(false) {}
/// Creates an instance with a \c true flag.
///
/// \note The only argument is ignored because it can be *the \c rosa::unit_t
/// value* only.
Optional(unit_t) : Value(true) {}
/// Creates an instance as a copy of another one.
///
/// \param Other the instance whose state to copy
Optional(const Optional &Other) = default;
/// Updates \p this object by copying the state of another one.
///
/// \param Other the instance whose state to copy
///
/// \return reference of the updated instance
Optional &operator=(const Optional &Other) = default;
/// Checks whether \p this object contains a \p true flag.
///
/// \return if \p this object contains a \p true flag.
explicit operator bool(void) const { return Value; }
/// Checks whether \p this object contains a \p false flag.
///
/// \return if \p this object contains a \p false flag.
bool operator!(void)const { return !Value; }
private:
/// The stored flag.
bool Value;
};
///@}
} // End namespace rosa
namespace std {
/// Returns the textual representation of any value of \c rosa::unit_t.
///
/// \return textual representation of \c rosa::UnitType.
inline std::string to_string(const rosa::unit_t &) { return "unit"; }
/// Dumps a \c rosa::Unit to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param U \c rosa::Unit to dump
///
/// \return \p OS after dumping \p U to it
inline ostream &operator<<(ostream &OS, const rosa::unit_t &U) {
OS << to_string(U);
return OS;
}
/// Returns the textual representation of any value of \c rosa::none_t.
///
/// \return textual representation of \c rosa::NoneType.
inline std::string to_string(const rosa::none_t &) { return "none"; }
/// Dumps a \c rosa::none_t to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param N \c rosa::none_t to dump
///
/// \return \p OS after dumping \p N to it
inline ostream &operator<<(ostream &OS, const rosa::none_t &N) {
OS << to_string(N);
return OS;
}
} // End namespace std
#endif // ROSA_SUPPORT_TYPES_HPP

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 16, 10:45 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
129118
Default Alt Text
(142 KB)

Event Timeline