Page MenuHomePhorge

No OneTemporary

Size
62 KB
Referenced Files
None
Subscribers
None
diff --git a/examples/messaging/messaging.cpp b/examples/messaging/messaging.cpp
index 7d1269b..640a2d1 100644
--- a/examples/messaging/messaging.cpp
+++ b/examples/messaging/messaging.cpp
@@ -1,126 +1,127 @@
//===-- examples/messaging/messaging.cpp ------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file examples/messaging/messaging.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017
+/// \date 2017-2019
///
/// \brief An example showcasing features related to the \c rosa::Message class.
///
//===----------------------------------------------------------------------===//
#include "rosa/config/version.h"
#include "rosa/core/MessageHandler.hpp"
#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"
using namespace rosa;
using namespace rosa::terminal;
int main(void) {
LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "messaging"
<< Color::Default << '\n';
auto &Log = LOG_INFO_STREAM << '\n';
// Message interface.
auto PMsg = Message::create<uint8_t, uint16_t>(1, 2);
auto &Msg = *PMsg;
Log << "Checking on a 'Message with TypeList<<uint8_t, uint16_t>>':"
<< "\n Size: " << Msg.Size
<< "\n Pos 0 is uint8_t: " << Msg.isTypeAt<uint8_t>(0)
<< "\n Pos 1 is uint16_t: " << Msg.isTypeAt<uint16_t>(1)
<< "\n Pos 2 is uint32_t: " << Msg.isTypeAt<uint32_t>(1)
<< "\n Value at pos 0: " << PRINTABLE(Msg.valueAt<uint8_t>(0))
<< "\n Value at pos 1: " << Msg.valueAt<uint16_t>(1) << "\n\n";
// MessageMatcher.
using MyMatcher = MsgMatcher<uint8_t, uint16_t>;
Log << "Matching against 'TypeList<uint8_t, uint16_t>':"
<< "\n matching: " << MyMatcher::doesStronglyMatch(Msg);
auto Vs = MyMatcher::extractedValues(Msg);
Log << "\n value: '(" << PRINTABLE(std::get<0>(Vs)) << ", "
<< std::get<1>(Vs) << ")'\n\n";
using MyWrongMatcher = MsgMatcher<uint8_t, uint8_t>;
Log << "Matching against 'TypeList<uint8_t, uint8_t>':"
<< "\n matching: " << MyWrongMatcher::doesStronglyMatch(Msg) << "\n\n";
using MyAtom = AtomConstant<atom("atom")>;
const MyAtom &A = MyAtom::Value;
using MyNAtom = AtomConstant<atom("noatom")>;
auto PAMsg = Message::create(A);
auto &AMsg = *PAMsg;
Log << "Checking on a 'Message with TypeList<AtomConstant<atom(\"atom\")>>':"
<< "\n Size: " << AMsg.Size
<< "\n Pos 0 is 'AtomValue': " << AMsg.isTypeAt<AtomValue>(0)
<< "\n Pos 0 is 'AtomConstant<atom(\"noatom\")>': "
<< AMsg.isTypeAt<MyNAtom>(0) << "\n\n";
using MyAtomMatcher = MsgMatcher<MyAtom>;
Log << "Matching against 'TypeList<AtomConstant<atom(\"atom\")>>':"
<< "\n matching: " << MyAtomMatcher::doesStronglyMatch(AMsg)
<< "\n value: '("
- << to_string(std::get<0>(MyAtomMatcher::extractedValues(AMsg))) << ")'"
+ << std::to_string(std::get<0>(MyAtomMatcher::extractedValues(AMsg)))
+ << ")'"
<< "\n\n";
using MyWrongAtomMatcher = MsgMatcher<MyNAtom>;
Log << "Matching against 'TypeList<AtomConstant<atom(\"noatom\")>>':"
<< "\n matching: " << MyWrongAtomMatcher::doesStronglyMatch(AMsg)
<< "\n\n";
// Invoker.
auto IP = Invoker::wrap(Invoker::F<MyAtom>([&Log](MyAtom) noexcept->void {
Log << "** Handling 'Message with "
"TypeList<AtomConstant<atom(\"atom\")>>'.\n";
}));
auto &I = *IP; // Get a reference from the pointer.
Log << "Invoking a function of signature 'void(AtomConstant<atom(\"atom\")>) "
"noexcept':"
<< "\n with 'Message with TypeList<uint8_t, uint16_t>'"
<< "\n does Message match Invoker: " << I.match(Msg)
<< "\n invoking...";
I(Msg);
Log << "\n with 'Message with TypeList<AtomConstant<atom(\"atom\")>>'..."
<< "\n does Message match Invoker: " << I.match(AMsg)
<< "\n invoking...";
I(AMsg);
Log << "\n\n";
// MessageHandler.
MessageHandler Handler{
Invoker::F<uint8_t, uint16_t>([&Log](uint8_t, uint16_t) {
Log << "** Handling 'Message with TypeList<uint8_t, uint16_t>'\n";
}),
Invoker::F<MyAtom>([&Log](MyAtom) {
Log << "** Handling 'Message with "
"TypeList<AtomConstant<atom(\"atom\")>>'\n";
})};
auto PANMsg = Message::create(MyNAtom::Value);
auto &ANMsg = *PANMsg;
Log << "Handling Messages with 'MessageHandler "
"{ Invoker::F<uint8_t, uint16_t>, "
"Invoker::F<AtomConstant<atom(\"atom\")>> }':"
<< "\n 'Message with TypeList<uint8_t, uint16_t>'"
<< "\n can handle: " << Handler.canHandle(Msg) << "\n handling...";
Handler(Msg);
Log << "\n 'Message with TypeList<AtomConstant<atom(\"atom\")>>'"
<< "\n can handle: " << Handler.canHandle(AMsg) << "\n handling...";
Handler(AMsg);
Log << "\n 'Message with TypeList<AtomConstant<atom(\"noatom\")>>'"
<< "\n can handle: " << Handler.canHandle(ANMsg)
<< "\n handling...";
Handler(ANMsg);
Log << "\n\n";
Log << "Terminating, destroying automatic variables.\n";
return 0;
}
diff --git a/include/rosa/core/Message.hpp b/include/rosa/core/Message.hpp
index 06b6c60..7a1fb74 100644
--- a/include/rosa/core/Message.hpp
+++ b/include/rosa/core/Message.hpp
@@ -1,259 +1,259 @@
//===-- rosa/core/Message.hpp -----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/core/Message.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Declaration of \c rosa::Message base-class.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_CORE_MESSAGE_HPP
#define ROSA_CORE_MESSAGE_HPP
#include "rosa/support/log.h"
#include "rosa/support/tokenized_storages.hpp"
#include "rosa/core/forward_declarations.h"
namespace rosa {
/// *Message* interface.
///
/// The interface provides means to check the type of the stored values, but
/// actual data is to be managed by derived implementations.
///
/// A \c rosa::Message instance is an immutable data object that obtains its
/// data upon creation and provides only constant references for the stored
/// values.
///
/// \note Any reference obtained from a \c rosa::Message instance remains valid
/// only as long as the owning \c rosa::Message object is not destroyed.
///
/// \todo Some member functions of \c rosa::Message duplicate member functions
/// of \c rosa::TokenizedStorage, which cannot be easily factored out into a
/// common base class due to eventual diamond inheritance issues in derived
/// classes. Could this duplication be avoided?
class Message {
protected:
/// Creates a new instance.
///
/// \note No implementation for empty list.
///
/// \tparam Type type of the mandatory first argument
/// \tparam Types types of any further arguments
///
/// \note the actual arguments are ignored by the constructor it is only
/// their type that matters. The actual values are supposed to be handled by
/// any implementation derived from \c rosa::Message.
///
/// \pre \p Type and \p Types are all built-in types and the number of stored
/// values does not exceed \c rosa::token::MaxTokenizableListSize.
template <typename Type, typename... Types>
Message(const Type &, const Types &...) noexcept;
/// No copying and moving of \c rosa::Message instances.
///@{
Message(const Message &) = delete;
Message(Message &&) = delete;
Message &operator=(const Message &) = delete;
Message &operator=(Message &&) = delete;
///@}
public:
/// Creates a \c rosa::message_t object from constant lvalue references.
///
/// \tparam Type type of the mandatory first argument
/// \tparam Types types of any further arguments
///
/// \param T the first value to include in the \c rosa::Message
/// \param Ts optional further values to include in the \c rosa::Message
///
/// \return new \c rosa::message_t object created from the given arguments
template <typename Type, typename... Types>
static message_t create(const Type &T, const Types &... Ts) noexcept;
/// Creates a \c rosa::message_t object from rvalue references.
///
/// \tparam Type type of the mandatory first argument
/// \tparam Types types of any further arguments
///
/// \param T the first value to include in the \c rosa::Message
/// \param Ts optional further values to include in the \c rosa::Message
///
/// \return new \c rosa::message_t object created from the given arguments
template <typename Type, typename... Types>
static message_t create(Type &&T, Types &&... Ts) noexcept;
/// Represents the types of the values stored in \p this object.
///
/// A valid, non-empty \c rosa::Token representing the types of the values
/// stored in \p this object.
const Token T;
/// The number of values stored in \p this object.
///
/// That is the number of types encoded in \c rosa::Message::T.
const token_size_t Size;
/// Destroys \p this object.
virtual ~Message(void);
/// 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 Type 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 Type
///
/// \pre \p Pos is a valid index:\code
/// Pos < Size
/// \endcode
template <typename Type> bool isTypeAt(const token_size_t Pos) const noexcept;
/// Gives a constant reference of a value of a given type stored at a given
/// index.
///
/// \tparam Type type to give a reference of
///
/// \param Pos index to set the reference for
///
/// \return constant reference of \p Type 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 Type:
/// \code
/// Pos < Size && isTypeAt<Type>(Pos)
/// \endcode
template <typename Type>
const Type &valueAt(const token_size_t Pos) const noexcept;
protected:
/// Provides an untyped pointer for the value at a given index.
///
/// \param Pos index to take a 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 const void *pointerTo(const token_size_t Pos) const noexcept = 0;
};
/// Nested namespace with implementation for \c rosa::Message, consider it
/// private.
namespace {
/// Template class for an implementation of \c rosa::Message.
///
/// \tparam Types types whose values are to be stored
template <typename... Types> class LocalMessage;
/// Implementation of the template \c rosa::LocalMessage providing facilities
/// for storing values as a \c rosa::Message object.
///
/// \tparam Type type of the first mandatory value of the \c rosa::Message
/// \tparam Types of any further values
template <typename Type, typename... Types>
class LocalMessage<Type, Types...> final
: public Message,
private TokenizedStorage<Type, Types...> {
public:
/// Creates an instance from constant lvalue references.
///
/// \param T the mandatory first value to store in the \c rosa::Message object
/// \param Ts optional further values to store in the \c rosa::Message object
LocalMessage(const Type &T, const Types &... Ts) noexcept
: Message(T, Ts...),
TokenizedStorage<Type, Types...>(T, Ts...) {
ASSERT(this->T == this->ST && Size == this->size()); // Sanity check.
}
/// Creates an instance from rvalue references.
///
/// \param T the mandatory first value to store in the \c rosa::Message object
/// \param Ts optional further values to store in the \c rosa::Message object
LocalMessage(Type &&T, Types &&... Ts) noexcept
: Message(T, Ts...),
TokenizedStorage<Type, Types...>(std::move(T), std::move(Ts)...) {
ASSERT(this->T == this->ST && Size == this->size()); // Sanity check.
}
/// Provides an untyped pointer for the constant value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return untyped pointer for the constant value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < Size
/// \endcode
const void *pointerTo(const token_size_t Pos) const noexcept override {
ASSERT(Pos < Size);
return TokenizedStorage<Type, Types...>::pointerTo(Pos);
}
/// Aborts the program!
///
/// Since \c rosa::Message instances are supposed to be immutable, the
/// non-const inherited function is overridden so that it aborts execution.
void *pointerTo(const token_size_t) noexcept override {
ROSA_CRITICAL("Unallowed operation of rosa::LocalMessage");
}
};
} // End namespace
template <typename Type, typename... Types>
Message::Message(const Type &, const Types &...) noexcept
: T(TypeToken<typename std::decay<Type>::type,
typename std::decay<Types>::type...>::Value),
Size(lengthOfToken(T)) {
ASSERT(validToken(T) &&
lengthOfToken(T) == (1 + sizeof...(Types))); // Sanity check.
- LOG_TRACE("Creating Message with Token(" + to_string(T) + ")");
+ LOG_TRACE("Creating Message with Token(" + std::to_string(T) + ")");
}
/// \note The implementation instantiates a private local template class
/// \c LocalMessage.
template <typename Type, typename... Types>
message_t Message::create(const Type &T, const Types &... Ts) noexcept {
return message_t(new LocalMessage<Type, Types...>(T, Ts...));
}
/// \note The implementation instantiates a private local template class
/// \c LocalMessage.
template <typename Type, typename... Types>
message_t Message::create(Type &&T, Types &&... Ts) noexcept {
return message_t(
new LocalMessage<Type, Types...>(std::move(T), std::move(Ts)...));
}
template <typename Type>
bool Message::isTypeAt(const token_size_t Pos) const noexcept {
ASSERT(Pos < Size);
Token TT = T;
dropNOfToken(TT, Pos);
return isHeadOfTokenTheSameType<Type>(TT);
}
template <typename Type>
const Type &Message::valueAt(const token_size_t Pos) const noexcept {
ASSERT(Pos < Size && isTypeAt<Type>(Pos));
return *static_cast<const Type *>(pointerTo(Pos));
}
} // End namespace rosa
#endif // ROSA_CORE_MESSAGE_HPP
diff --git a/include/rosa/support/atom.hpp b/include/rosa/support/atom.hpp
index 60fbe06..1dfe3e0 100644
--- a/include/rosa/support/atom.hpp
+++ b/include/rosa/support/atom.hpp
@@ -1,179 +1,209 @@
//===-- rosa/support/atom.hpp -----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/atom.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017
+/// \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.
/// \todo Check license.
///
/// *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"
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 rosa::AtomValue into \c std::string.
-///
-/// \param What value to convert
-///
-/// \return \c std::string encoded in \p What
-std::string to_string(const AtomValue &What);
-
/// 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) {}
/// 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 <AtomValue V> std::string to_string(const AtomConstant<V> &) {
+template <rosa::AtomValue V> string to_string(const rosa::AtomConstant<V> &) {
return to_string(V);
}
-} // End namespace rosa
+/// 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/type_numbers.hpp b/include/rosa/support/type_numbers.hpp
index 2d5f464..cc85cc7 100644
--- a/include/rosa/support/type_numbers.hpp
+++ b/include/rosa/support/type_numbers.hpp
@@ -1,225 +1,240 @@
//===-- rosa/support/type_numbers.hpp ---------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/type_numbers.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facilities for registering supported types and representing them with
/// numbers.
///
/// \note This implementation is partially based on the \c type_number
/// implementation of CAF.
/// \todo Check license.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TYPE_NUMBERS_HPP
#define ROSA_SUPPORT_TYPE_NUMBERS_HPP
#include "rosa/support/atom.hpp"
#include "rosa/support/math.hpp"
#include "rosa/support/squashed_int.hpp"
#include "rosa/support/type_helper.hpp"
#include "rosa/support/types.hpp"
#include <array>
#include <string>
namespace rosa {
/// Compile-time list of all built-in types.
/// \note Appending new types to the end of this list maintains backward
/// compatibility in the sense that old builtin types have the same type number
/// associated to them in both the old and new versions. But changing any of
/// the already present types in the list breaks that backward compatibility.
/// Should compatibility be broken, step \c rosa::TypeNumberVersion below!
/// \note Keep this list in sync with the definition of
/// \c rosa::NumberedTypeNames.
/// \note The built-in types are explicitly listed in the definition of
/// rosa::deluxe::DeluxeAgent. Keep those definitions in sync with this list.
using BuiltinTypes = TypeList<AtomValue, ///< atom
int16_t, ///< i16
int32_t, ///< i32
int64_t, ///< i64
int8_t, ///< i8
long double, ///< ldouble
std::string, ///< str
uint16_t, ///< u16
uint32_t, ///< u32
uint64_t, ///< u64
uint8_t, ///< u8
unit_t, ///< unit
bool, ///< bool
double, ///< double
float ///< float
>;
/// Indicates the version number of \c rosa::BuiltinTypes.
///
/// Software with the same version number are supposed to have backward
/// compatible type numbering.
///
/// \sa \c rosa::BultinTypes on backward compatibility.
constexpr size_t TypeNumberVersion = 0;
/// The number of built-in types.
static constexpr size_t NumberOfBuiltinTypes =
TypeListSize<BuiltinTypes>::Value;
/// Anonymous namespace for helper facilities, consider it private.
namespace {
/// Tells if a type is not \c rosa::NoneType.
///
/// \tparam T the type to check
template <typename T> struct IsNotNoneType {
/// Denotes if \p T is the \c rosa::NoneType or not.
static constexpr bool Value = !std::is_same<T, NoneType>::value;
};
} // End namespace
/// Integer type to store type numbers.
/// \note The narrowest unsigned integer type that is wide enough to represent
/// \c NumberOfBuiltinTypes different values.
using type_nr_t = typename TypeListFind<
typename TypeListDrop<log2(NumberOfBuiltinTypes) / 8 + 1,
IntegerTypesBySize>::Type,
IsNotNoneType>::Type::Second;
/// Turn \c rosa::type_nr_t into a strongly typed enumeration.
///
/// Values of \c rosa::type_nr_t casted to \c rosa::TypeNumbers can be used in a
/// type-safe way.
enum class TypeNumber : type_nr_t {};
/// A type to cast type numbers into in order to output them to streams as
/// numbers and not ASCII-codes.
///
/// \note Use it for safety, necessary for printing \c uint8_t values.
using printable_tn_t = printable_t<type_nr_t>;
/// Casts a \c rosa::TypeNumber into \c rosa::printable_tn_t.
///
/// \param TN \c rosa::TypeNumber to cast.
#define PRINTABLE_TN(TN) static_cast<printable_tn_t>(TN)
-/// Converts a \c rosa::TypeNumber into \c std::string.
-///
-/// \param TN \c rosa::TypeNumber to convert
-///
-/// \return \c std::string representing \p TN
-inline std::string to_string(const TypeNumber TN) {
- return std::to_string(static_cast<type_nr_t>(TN));
-}
-
/// \name TypeNumberOf
/// \brief Computes \c rosa::TypeNumber for a type.
///
/// The \c rosa::TypeNumber for a type \c T can be obtained as \code
/// TypeNumberOf<T>::Value
/// \endcode
///
/// \note \c rosa::TypeNumber for a type is based on the corresponding squashed
/// type, except for \c rosa::AtomConstant types.
///
/// \sa \c rosa::SquashedType
///
/// \note \c rosa::TypeNumber is the index of the type in \c rosa::BuiltinTypes
/// starting from \c 1; index \c 0 indicates a non-builtin type.
///@{
/// Definition of the template for the general case.
///
/// \tparam T type to get \c rosa::TypeNumber for
template <typename T> struct TypeNumberOf {
static constexpr TypeNumber Value = static_cast<TypeNumber>(
TypeListIndexOf<BuiltinTypes, squashed_t<T>>::Value + 1);
};
/// Specialization for \c rosa::AtomConstant.
///
/// \note For a \c rosa::AtomConstant type, \c rosa::TypeNumber is based on the
/// \c rosa::AtomValue wrapped into the actual \c rosa::AtomConstant.
template <AtomValue V> struct TypeNumberOf<AtomConstant<V>> {
static constexpr TypeNumber Value = TypeNumberOf<AtomValue>::Value;
};
///@}
// clang-format off
/// List of type names for all builtin-types, indexed via \c rosa::TypeNumber.
///
/// \note Keep this definition in sync with \c rosa::BuiltinTypes.
constexpr std::array<const char *, NumberOfBuiltinTypes> NumberedTypeNames {{
"atom",
"i16",
"i32",
"i64",
"i8",
"ldouble",
"str",
"u16",
"u32",
"u64",
"u8",
"unit",
"bool",
"double",
"float"
}};
// clang-format on
/// Tells if a \c rosa::TypeNumber is valid in the software.
///
/// \note A \c rosa::TypeNumber generated by an incompatible version may be
/// valid but may denote a type that is different from the \c rosa::TypeNumber
/// denotes in the current software. That is why this validation needs to be
/// done in connection to checking \c rosa::TypeNumberVersion as well.
///
/// \param TN \c rosa::TypeNumber to validate in the context of the current
/// software
///
/// \return Whether \p TN is valid in the current software
constexpr bool validTypeNumber(const TypeNumber TN) {
// \todo Duplication of static_cast into a const variable would be
// possible in C++14.
return 0 < static_cast<type_nr_t>(TN) &&
static_cast<type_nr_t>(TN) <= NumberOfBuiltinTypes;
}
/// Provides information about the type corresponding to a \c rosa::TypeNumber.
///
/// \tparam TN \c rosa::TypeNumber to get information for
///
/// \pre Statically, \p TN is a valid \c rosa::TypeNumber:
/// \code
/// validTypeNumber(TN)
/// \endcode
template <TypeNumber TN> struct TypeForNumber {
STATIC_ASSERT(validTypeNumber(TN), "not a valid type number");
/// \p TN as \c rosa::type_nr_t.
static constexpr type_nr_t TNI = static_cast<type_nr_t>(TN);
/// The builtin-type corresponding to \p TN.
using Type = typename TypeListAt<BuiltinTypes, TNI - 1>::Type;
/// The size of \c Type.
static constexpr size_t Size = sizeof(Type);
/// Textual representation of the builtin-type.
static constexpr const char *Name = NumberedTypeNames[TNI - 1];
};
} // End namespace rosa
+namespace std {
+
+/// Converts a \c rosa::TypeNumber into \c std::string.
+///
+/// \param TN \c rosa::TypeNumber to convert
+///
+/// \return \c std::string representing \p TN
+inline string to_string(const rosa::TypeNumber TN) {
+ return to_string(static_cast<rosa::type_nr_t>(TN));
+}
+
+/// Dumps a \c rosa::TypeNumber to a given \c std::ostream.
+///
+/// \param [in,out] OS output stream to dump to
+/// \param TN \c rosa::TypeNumber to dump
+///
+/// \return \p OS after dumping \p TN to it
+inline ostream &operator<<(ostream &OS, const rosa::TypeNumber &TN) {
+ OS << to_string(TN);
+ return OS;
+}
+
+} // End namespace std
+
#endif // ROSA_SUPPORT_TYPE_NUMBERS_HPP
diff --git a/include/rosa/support/type_token.hpp b/include/rosa/support/type_token.hpp
index cc4aeaf..99f2cec 100644
--- a/include/rosa/support/type_token.hpp
+++ b/include/rosa/support/type_token.hpp
@@ -1,306 +1,321 @@
//===-- rosa/support/type_token.hpp -----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/type_token.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facilities for encoding TypeLists as unsigned integer values.
///
/// \note **On the compatibility between different versions of the type token
/// implementation:**
/// Different software versions produce compatible type tokens as long as
/// *backward compatibility* of \c rosa::BuiltinTypes is maintained (denoted by
/// \c rosa::TypeNumberVersion) and the type token implementation uses the same
/// type as \c rosa::token_t (boiling down to the same \c rosa::token::TokenBits
/// value) and the same \c rosa::token::RepresentationBits value. Thus,
/// interacting software need to cross-validate the aforementioned values to
/// check compatibility. Interoperation between compatible sofware is limited
/// to backward compatiblity, that is builtin types defined in both software
/// versions are handled correctly but a newer system may produce a type token
/// which is invalid in an old one. Therefore, tokens obtained from a compatible
/// remote system need to be validated.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TYPE_TOKEN_HPP
#define ROSA_SUPPORT_TYPE_TOKEN_HPP
#include "rosa/support/type_numbers.hpp"
namespace rosa {
/// Integer type to store type tokens.
///
/// \note The trade-off between the binary overhead of type encoding and the
/// maximal size of encodable lists can be tuned by using unsigned integer types
/// of different widths as \c rosa::token_t.
using token_t = uint64_t;
/// Sanity check in case someone would change \c rosa::token_t.
STATIC_ASSERT(std::is_unsigned<token_t>::value,
"token_t is not an unsigned integer");
/// Turn \c rosa::token_t into a strongly typed enumeration.
///
/// Values of \c rosa::token_t casted to \c rosa::Token can be used in a
/// type-safe way.
enum class Token : token_t {};
/// A type to cast tokens into in order to output them to streams as
/// numbers and not ASCII-codes.
///
/// \note Use it for safety, necessary for printing \c uint8_t values.
using printable_token_t = printable_t<token_t>;
/// Casts a \c rosa::Token into \c rosa::printable_token_t.
///
/// \param T \c rosa::Token to cast
#define PRINTABLE_TOKEN(T) static_cast<printable_token_t>(T)
-/// Converts a \c rosa::Token into \c std::string.
-///
-/// \param T \c rosa::Token to convert
-///
-/// \return \c std::string representing \p T
-inline std::string to_string(const Token T) {
- return std::to_string(static_cast<token_t>(T));
-}
-
/// Encloses constants related to the implementation of \c rosa::Token.
namespace token {
/// The number of bits in one \c rosa::Token.
constexpr size_t TokenBits = sizeof(Token) * 8;
/// The number of bits a builtin type can be uniquely encoded into, that is any
/// valid \c rosa::TypeNumber can fit into.
///
/// \note There is one extra bit position added for encoding so that providing a
/// better chance to maintain backward comaptibility when \c rosa::BuiltinTypes
/// is extended.
constexpr size_t RepresentationBits = log2(NumberOfBuiltinTypes) + 1;
/// Maximal size of uniquely tokenizable \c rosa::TypeList.
constexpr size_t MaxTokenizableListSize = TokenBits / RepresentationBits;
} // End namespace token
/// Integer type to store length of a \c rosa::Token.
///
/// \note The narrowest unsigned integer type that is wide enough to
/// represent \c rosa::token::MaxTokenizableListSize different values.
using token_size_t = typename TypeListFind<
typename TypeListDrop<log2(token::MaxTokenizableListSize) / 8 + 1,
IntegerTypesBySize>::Type,
IsNotNoneType>::Type::Second;
/// \defgroup TypeListTokenImpl Implementation of rosa::TypeListToken
///
/// \brief Generates a \c rosa::Token for a squashed \c rosa::TypeList.
///
/// \note Only to be used by the implementation of \c rosa::TypeListToken.
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to generate \c rosa::Token for
template <typename List> struct TypeListTokenImpl;
/// Specialization for \c rosa::EmptyTypeList.
template <> struct TypeListTokenImpl<EmptyTypeList> {
static constexpr Token Value = static_cast<Token>(0);
};
/// Specialization for a non-empty \c rosa::TypeList.
template <typename T, typename... Ts>
struct TypeListTokenImpl<TypeList<T, Ts...>> {
static constexpr TypeNumber TN = TypeNumberOf<T>::Value;
// Check if the generated type number is valid.
STATIC_ASSERT(validTypeNumber(TN), "non-builtin type");
static constexpr Token Value = static_cast<Token>(
(static_cast<token_t>(TypeListTokenImpl<TypeList<Ts...>>::Value)
<< token::RepresentationBits) |
static_cast<type_nr_t>(TN));
};
///@}
/// \name TypeListToken
///
/// \brief Generates a \c rosa::Token for a \c rosa::TypeList.
///
/// \c rosa::Token for a \c rosa::TypeList \c List can be obtained as \code
/// TypeListToken<List>::Value
/// \endcode
///
/// \note The \c rosa::TypeList cannot have more than
/// \c rosa::token::MaxTokenizableListSize elements and must be a subset of
/// \c rosa::BuiltinTypes with respect to squashed integers.
///
/// \note A generated \c rosa::Token uniquely represents a list of types, except
/// for \c rosa::AtomConstant types. Observe that any \c rosa::AtomConstant is
/// encoded as the type \c rosa::AtomValue. The type information on all separate
/// \c rosa::AtomConstant types are lost and replaced by the \c rosa::AtomValue
/// type whose actual value needs to be used in order to obtain the original
/// \c rosa::AtomConstant type and so the full type information on the encoded
/// \c rosa::TypeList.
///
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to generate \c rosa::Token for
template <typename List> struct TypeListToken;
/// Implementation using \c rosa::TypeListTokenImpl.
template <typename... Ts> struct TypeListToken<TypeList<Ts...>> {
/// \note \c rosa::TypeNumber is computed against \c rosa::squased_t, so let's
/// do the same here.
using List = typename SquashedTypeList<TypeList<Ts...>>::Type;
/// Check the length of the list here.
/// \note Type validation is done one-by-one in \c rosa::TypeListTokenImpl.
STATIC_ASSERT((TypeListSize<List>::Value <= token::MaxTokenizableListSize),
"too long list of types");
/// The \c rosa::Token for \p List.
static constexpr Token Value = TypeListTokenImpl<List>::Value;
};
///@}
/// Convenience template to generate \c rosa::Token for a list of types.
template <typename... Ts> using TypeToken = TypeListToken<TypeList<Ts...>>;
/// Tells if a given \c rosa::Token is valid.
///
/// A \c rosa::Token is considered valid if it can be decoded by the current
/// software.
///
/// \note Validation gives a correct result only when \p T was generated by a
/// compatible software.
///
/// \sa Note for type_token.hpp on compatibility.
///
/// \param T \c rosa::Token to validate
///
/// \return if \p T is valid
bool validToken(const Token T);
/// Tells if a \c rosa::Token does encode an empty list of types.
///
/// \param T \c rosa::Token to check
///
/// \return if \p T encodes an empty list of types
bool emptyToken(const Token T);
/// Tells how many types are encoded in a \c rosa::Token.
///
/// \param T \c rosa::Token to check
///
/// \return how many types are encoded in \p T
token_size_t lengthOfToken(const Token T);
/// Tells the full memory size of the types encoded in a \c rosa::Token.
///
/// The full memory size of the types encoded in a \c rosa::Token is the sum of
/// the separate memory sizes of all the types encoded in the \c rosa::Token.
///
/// \param T \c rosa::Token to check
///
/// \return full memory size of the types encoded in \p T
///
/// \pre \p T is valid:\code
/// validToken(T)
/// \endcode
size_t sizeOfValuesOfToken(const Token T);
/// Extracts the \c rosa::TypeNumber of the first encoded type of a
/// \c rosa::Token.
///
/// \note The returned type number is not validated.
///
/// \param T \c rosa::Token to take the first \c rosa::TypeNumber from
///
/// \return the first \c rosa::TypeNumber encoded in \p T
inline TypeNumber headOfToken(const Token T) {
return static_cast<TypeNumber>(static_cast<token_t>(T) &
((1 << token::RepresentationBits) - 1));
}
/// Tells the memory size of the first type encoded in a \c rosa::Token.
///
/// \param T \c rosa::Token to check the first encoded type of
///
/// \return memory size of the first type encoded in \p T
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
size_t sizeOfHeadOfToken(const Token T);
/// Gives the textual representation of the first type encoded in a
/// \c rosa::Token.
///
/// \param T \c rosa::Token to take the name of its first encoded type
///
/// \return textual representation of the first type encoded in \p T
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
const char *nameOfHeadOfToken(const Token T);
/// Updates a \c rosa::Token by dropping its first encoded type.
///
/// \param [in,out] T \c rosa::Token to drop the first encoded type of
void dropHeadOfToken(Token &T);
/// Updates a \c rosa::Token by dropping a number of its first encoded types
///
/// \param [in,out] T \c rosa::Token to drop the first \p N encoded types of
/// \param N the number of types to drop from \p T
void dropNOfToken(Token &T, const size_t N);
/// Tells what type is encoded at Position \p Pos in the \c rosa::Token \p T
///
/// \param T \c rosa::Token to check
/// \param Pos the position to check
///
/// \return \c rosa::TypeNumber of the type encodeded at position \p Pos of \c
/// rosa::Token \p T
///
/// \pre \p T is valid and it encodes \p Pos types: \code
/// validToken(T) && Pos < static_cast<size_t>(lengthOfToken(T))
/// \endcode
inline TypeNumber typeAtPositionOfToken(const Token T, const size_t Pos) {
ASSERT(validToken(T) && Pos < static_cast<size_t>(lengthOfToken(T)));
Token TT = T;
dropNOfToken(TT, Pos);
return headOfToken(TT);
}
/// Tells if the first encoded type of a \c rosa::Token is a given type.
///
/// \tparam Type type to match the first encoded type of \p T against
///
/// \param T \c rosa::Token whose first encoded type is to be matched against
/// \p Type
///
/// \return if the first encoded type of \p T is \p Type
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
template <typename Type> bool isHeadOfTokenTheSameType(const Token T) {
ASSERT(!emptyToken(T) && validToken(T));
return TypeNumberOf<Type>::Value == headOfToken(T);
}
} // End namespace rosa
+namespace std {
+
+/// Converts a \c rosa::Token into \c std::string.
+///
+/// \param T \c rosa::Token to convert
+///
+/// \return \c std::string representing \p T
+inline string to_string(const rosa::Token T) {
+ return to_string(static_cast<rosa::token_t>(T));
+}
+
+/// Dumps a \c rosa::Token to a given \c std::ostream.
+///
+/// \param [in,out] OS output stream to dump to
+/// \param T \c rosa::Token to dump
+///
+/// \return \p OS after dumping \p N to it
+inline ostream &operator<<(ostream &OS, const rosa::Token &T) {
+ OS << to_string(T);
+ return OS;
+}
+
+} // End namespace std
+
#endif // ROSA_SUPPORT_TYPE_TOKEN_HPP
diff --git a/include/rosa/support/types.hpp b/include/rosa/support/types.hpp
index e00e04b..eb6a3b2 100644
--- a/include/rosa/support/types.hpp
+++ b/include/rosa/support/types.hpp
@@ -1,524 +1,550 @@
//===-- rosa/support/types.hpp ----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/types.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017
+/// \date 2017-2019
///
/// \brief Implementation of some basic convenience types.
///
/// \note This implementation is partially based on the implementation of
/// corresponding parts of CAF.
/// \todo Check license.
///
//===----------------------------------------------------------------------===//
#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 {}
/// Copy-constructor, needs to do nothing.
constexpr UnitType(const UnitType &) noexcept {}
};
/// 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
-/// 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 unit_t &) { return "unit"; }
-
/// \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) {}
/// 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
-/// 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 none_t &) { return "none"; }
-
/* ************************************************************************** *
* 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
diff --git a/lib/core/Unit.cpp b/lib/core/Unit.cpp
index e693624..007ef55 100644
--- a/lib/core/Unit.cpp
+++ b/lib/core/Unit.cpp
@@ -1,53 +1,53 @@
//===-- core/Unit.cpp -------------------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file core/Unit.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017
+/// \date 2017-2019
///
/// \brief Implementation of rosa/core/Unit.h.
///
//===----------------------------------------------------------------------===//
#include "rosa/core/Unit.h"
#include "rosa/core/System.hpp" // NOLINT
#include "rosa/support/debug.hpp"
#include "rosa/support/log.h"
namespace rosa {
Unit::Unit(const AtomValue Kind, const id_t Id, const std::string &Name,
System &S) noexcept : Kind(Kind),
Id(Id),
Name(Name),
S(S),
FullName(Name + "@" + S.name()) {
ASSERT(!Name.empty());
- LOG_TRACE("Constructing Unit '" + FullName + "' of kind '" + to_string(Kind) +
- "'");
+ LOG_TRACE("Constructing Unit '" + FullName + "' of kind '" +
+ std::to_string(Kind) + "'");
}
Unit::~Unit(void) { LOG_TRACE("Destroying Unit '" + FullName + "'"); }
/// The default implementation of \c rosa::Unit::dump emits
/// \c rosa::Unit::FullName.
std::string Unit::dump(void) const noexcept {
LOG_TRACE("Dumping Unit '" + FullName + "'");
return "[Unit] " + FullName;
}
System &Unit::system(void) const noexcept { return S; }
std::ostream &operator<<(std::ostream &OS, const Unit &U) {
OS << U.dump();
return OS;
}
} // End namespace rosa
diff --git a/lib/support/atom.cpp b/lib/support/atom.cpp
index ee48d3d..9ef7c43 100644
--- a/lib/support/atom.cpp
+++ b/lib/support/atom.cpp
@@ -1,55 +1,59 @@
//===-- support/atom.cpp ----------------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file support/atom.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017
+/// \date 2017-2019
///
/// \brief Implementation of non-static part of atom facilities of
/// rosa/support/atom.hpp.
///
/// \note This implementation is based on the `atom` implementation of CAF.
/// \todo Check license.
///
//===----------------------------------------------------------------------===//
#include "rosa/support/atom.hpp"
#include <cstring>
namespace rosa {
-std::string to_string(const AtomValue &What) {
- auto X = static_cast<atom_t>(What);
- std::string S;
- S.reserve(MaxAtomLength + 1);
+AtomValue atom_from_string(const std::string &S) {
+ if (S.size() > MaxAtomLength) {
+ return atom("");
+ }
+ char AtomBuf[MaxAtomLength + 1];
+ std::memcpy(AtomBuf, S.c_str(), S.size());
+ AtomBuf[S.size()] = '\0';
+ return atom(AtomBuf);
+}
+
+} // End namespace rosa
+
+namespace std {
+
+string to_string(const rosa::AtomValue &What) {
+ auto X = static_cast<rosa::atom_t>(What);
+ string S;
+ S.reserve(rosa::MaxAtomLength + 1);
// Don't read characters before we found the leading 0xF.
// First four bits set?
bool ReadChars = ((X & 0xF000000000000000) >> 60) == 0xF;
uint64_t Mask = 0x0FC0000000000000;
for (int BitShift = 54; BitShift >= 0; BitShift -= 6, Mask >>= 6) {
if (ReadChars) {
- S += AtomDecodingTable[(X & Mask) >> BitShift];
+ S += rosa::AtomDecodingTable[(X & Mask) >> BitShift];
} else if (((X & Mask) >> BitShift) == 0xF) {
ReadChars = true;
}
}
return S;
}
-AtomValue atom_from_string(const std::string &S) {
- if (S.size() > MaxAtomLength) {
- return atom("");
- }
- char AtomBuf[MaxAtomLength + 1];
- std::memcpy(AtomBuf, S.c_str(), S.size());
- AtomBuf[S.size()] = '\0';
- return atom(AtomBuf);
-}
-
-} // End namespace rosa
+} // End namespace std

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 29, 5:52 PM (1 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
242456
Default Alt Text
(62 KB)

Event Timeline