From 7e98e4d7d4c5b43e418783b1e5e683c11151a6ad Mon Sep 17 00:00:00 2001 From: ugeorge Date: Tue, 15 Mar 2016 02:27:54 +0100 Subject: [PATCH 01/18] started complex type introspection. Works nicely. --- src/forsyde/abssemantics.hpp | 6 +- src/forsyde/types.hpp | 128 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/src/forsyde/abssemantics.hpp b/src/forsyde/abssemantics.hpp index cc881b5..6f8dbcf 100644 --- a/src/forsyde/abssemantics.hpp +++ b/src/forsyde/abssemantics.hpp @@ -89,7 +89,7 @@ class signal: public sc_fifo //! Returns the name of the token type virtual const char* token_type() const { - return get_type_name(); + return get_smart_type_name(); } virtual std::string moc() const = 0; @@ -149,7 +149,7 @@ class in_port: public sc_fifo_in //! Returns the plain name of the token type virtual const char* token_type() const { - return get_type_name(); + return get_smart_type_name(); } #endif }; @@ -189,7 +189,7 @@ class out_port: public sc_fifo_out //! Returns the name of the actual type (not abst_ext version) virtual const char* token_type() const { - return get_type_name(); + return get_smart_type_name(); } #endif }; diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index 94bd0ba..50253ab 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -14,6 +14,8 @@ #ifndef TYPES_HPP #define TYPES_HPP +#include + /*! \file types.hpp * \brief Provides facilities for basic type introspection * @@ -29,6 +31,13 @@ #pragma once template const char* get_type_name() {return typeid(T).name();} + +template +using Vector = std::vector; + +template +using Tuple = std::tuple; + // Specialization for each type #define DEFINE_TYPE(X) \ template<>const char* get_type_name(){return #X;} @@ -54,6 +63,125 @@ DEFINE_TYPE(long double); DEFINE_TYPE(wchar_t); +template std::string get_type_size() {return std::to_string(sizeof(T));} + + +struct type_info { + std::string name = ""; + std::string size = ""; + + void surround(const std::string& before, const std::string& after) { + name = before + name + after; + size = before + size + after; + } + + void concat(type_info& rhs) { + name += rhs.name; + size += rhs.size; + } +}; + +class SmartTypes { +public: + template + struct base_type { + static inline void get(type_info& info) { + std::cout<< "base nothing" << std::endl; + info.name += get_type_name(); + info.size += get_type_size(); + } + }; + + + template + struct base_type> { + static inline void get(type_info& info) { + std::cout<< "base vector" << std::endl; + type_context::get(info); + info.size += ":" + std::to_string(sizeof(T)); + } + }; + + template + struct base_type> { + static inline void get(type_info& info) { + std::cout<< "base tuple" << std::endl; + type_context>::get(info); + } + }; + + template + struct traverse_tuple {}; + + template + struct traverse_tuple>{ + static inline void get(type_info& info) { + std::cout<< "traversal" << std::endl; + type_context::get(info); + info.surround("", ","); + traverse_tuple>::get(info); + } + }; + + template + struct traverse_tuple<1, Tuple> { + static inline void get(type_info& info) { + std::cout<< "traversal end" << std::endl; + type_context::get(info); + } + }; + + + template + struct type_context { + static inline void get(type_info& info) { + std::cout<< "context nothing" << std::endl; + base_type::get(info); + } + }; + + + template + struct type_context> { + static inline void get(type_info& info) { + std::cout<< "context vector" << std::endl; + type_info new_vector; + base_type>::get(new_vector); + std::cout<< "end vector" << std::endl; + new_vector.surround("[","]"); + info.concat(new_vector); + } + }; + + template + struct type_context> { + static inline void get(type_info& info) { + std::cout<< "context tuple" << std::endl; + type_info new_tuple; + traverse_tuple>::get(new_tuple); + new_tuple.surround("(",")"); + info.concat(new_tuple); + + } + }; + + template + static inline type_info get_smart_type_info() { + type_info info; + type_context::get(info); + return info; + }; +}; + +template +const char* get_smart_type_name() { + std::string str = SmartTypes::get_smart_type_info().name; + char * writable = new char[str.size() + 1]; + std::copy(str.begin(), str.end(), writable); + writable[str.size()] = '\0'; + return writable; +} + //~ } #endif From 60a0d024d710f97aaba953a77d9bec7b7346533d Mon Sep 17 00:00:00 2001 From: ugeorge Date: Tue, 15 Mar 2016 15:08:47 +0100 Subject: [PATCH 02/18] introspective types with xml output --- src/forsyde/abssemantics.hpp | 13 ++- src/forsyde/types.hpp | 177 ++++++++++++++++++----------------- src/forsyde/xml.hpp | 36 ++++++- 3 files changed, 128 insertions(+), 98 deletions(-) diff --git a/src/forsyde/abssemantics.hpp b/src/forsyde/abssemantics.hpp index 6f8dbcf..7727320 100644 --- a/src/forsyde/abssemantics.hpp +++ b/src/forsyde/abssemantics.hpp @@ -14,6 +14,8 @@ #ifndef ABSSEMANTICS_HPP #define ABSSEMANTICS_HPP +#include "types.hpp" + /*! \file abssemantics.hpp * \brief The common abstract semantics for all MoCs. * @@ -49,7 +51,7 @@ class introspective_channel { public: //! Name of the tokens in the channels - virtual const char* token_type() const = 0; + virtual const char* token_type(IntrospectiveType&) const = 0; // TODO: remove if proved not to be needed //~ //! Size of the tokens in the channels @@ -87,9 +89,10 @@ class signal: public sc_fifo // TODO: remove if proved not to be needed //! Returns the name of the token type - virtual const char* token_type() const + virtual const char* token_type(IntrospectiveType& type_parser) const { - return get_smart_type_name(); + type_parser.traverse(); + return get_type_name(); } virtual std::string moc() const = 0; @@ -149,7 +152,7 @@ class in_port: public sc_fifo_in //! Returns the plain name of the token type virtual const char* token_type() const { - return get_smart_type_name(); + return get_type_name(); } #endif }; @@ -189,7 +192,7 @@ class out_port: public sc_fifo_out //! Returns the name of the actual type (not abst_ext version) virtual const char* token_type() const { - return get_smart_type_name(); + return get_type_name(); } #endif }; diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index 50253ab..fad7548 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -15,6 +15,11 @@ #define TYPES_HPP #include + #include +#include "rapidxml_print.hpp" + + +using namespace rapidxml; /*! \file types.hpp * \brief Provides facilities for basic type introspection @@ -27,9 +32,12 @@ //~ namespace ForSyDe //~ { + // The general case uses RTTI (if the type is not registered explicitly) #pragma once -template const char* get_type_name() {return typeid(T).name();} +template const char* get_type_name() { + return typeid(T).name(); +} template @@ -63,50 +71,61 @@ DEFINE_TYPE(long double); DEFINE_TYPE(wchar_t); -template std::string get_type_size() {return std::to_string(sizeof(T));} +class IntrospectiveType { +public: + IntrospectiveType(xml_document<>* xml_doc, xml_node<>* root) : xml_doc(xml_doc), root(root) { + const_name = (char*)"name"; + const_data_type = (char*)"data_type"; + const_primitive = (char*)"primitive"; + const_vector = (char*)"vector"; + const_tuple = (char*)"tuple"; + const_size = (char*)"size"; + const_length = (char*)"length"; + } + ~IntrospectiveType(){} +public: + template + inline void traverse() { + // Get the list of module children (ports and other processes) -struct type_info { - std::string name = ""; - std::string size = ""; + for (auto child = root->first_node(); child; child = child->next_sibling()) { + if (child->first_attribute(const_name)->value() == get_type_name() ) return; + } - void surround(const std::string& before, const std::string& after) { - name = before + name + after; - size = before + size + after; - } + xml_node<> *type_node = allocate_append_node(root, const_data_type); + allocate_append_attribute(type_node, const_data_type, get_type_name()); - void concat(type_info& rhs) { - name += rhs.name; - size += rhs.size; - } -}; + add_type_node::get(type_node); + }; -class SmartTypes { -public: template - struct base_type { - static inline void get(type_info& info) { - std::cout<< "base nothing" << std::endl; - info.name += get_type_name(); - info.size += get_type_size(); + struct add_type_node { + inline void get (xml_node<>* parent) { + xml_node<> *primitive_node = allocate_append_node(parent, const_primitive); + allocate_append_attribute(primitive_node, const_name, get_type_name()); + allocate_append_attribute(primitive_node, const_size, size_to_char(sizeof(T))); } }; - template - struct base_type> { - static inline void get(type_info& info) { - std::cout<< "base vector" << std::endl; - type_context::get(info); - info.size += ":" + std::to_string(sizeof(T)); + struct add_type_node> { + inline void get (xml_node<>* parent) { + xml_node<> *vector_node = allocate_append_node(parent, const_vector); + add_type_node::get(vector_node); + + size_t child_size = char_to_size(vector_node->first_node()->first_attribute(const_size)->value()); + allocate_append_attribute(vector_node, const_length, size_to_char(sizeof(T)/child_size)); + allocate_append_attribute(vector_node, const_size, size_to_char(sizeof(T))); } }; template - struct base_type> { - static inline void get(type_info& info) { - std::cout<< "base tuple" << std::endl; - type_context>::get(info); + struct add_type_node> { + inline void get (xml_node<>* parent) { + xml_node<> *tuple_node = allocate_append_node(parent, const_tuple); + traverse_tuple>(tuple_node); + allocate_append_attribute(tuple_node, const_size, size_to_char(sizeof(T))); } }; @@ -115,73 +134,55 @@ class SmartTypes { template struct traverse_tuple>{ - static inline void get(type_info& info) { - std::cout<< "traversal" << std::endl; - type_context::get(info); - info.surround("", ","); - traverse_tuple>::get(info); + inline void get (xml_node<>* parent) { + add_type_node(parent); + traverse_tuple>(parent); } }; template struct traverse_tuple<1, Tuple> { - static inline void get(type_info& info) { - std::cout<< "traversal end" << std::endl; - type_context::get(info); - } - }; - - - template - struct type_context { - static inline void get(type_info& info) { - std::cout<< "context nothing" << std::endl; - base_type::get(info); + inline void get (xml_node<>* parent) { + add_type_node(parent); } }; - - template - struct type_context> { - static inline void get(type_info& info) { - std::cout<< "context vector" << std::endl; - type_info new_vector; - base_type>::get(new_vector); - std::cout<< "end vector" << std::endl; - new_vector.surround("[","]"); - info.concat(new_vector); - } - }; - - template - struct type_context> { - static inline void get(type_info& info) { - std::cout<< "context tuple" << std::endl; - type_info new_tuple; - traverse_tuple>::get(new_tuple); - new_tuple.surround("(",")"); - info.concat(new_tuple); - - } - }; - - template - static inline type_info get_smart_type_info() { - type_info info; - type_context::get(info); - return info; - }; + //! The RapidXML DOM + xml_document<>* xml_doc; + xml_node<>* root; + + //! Some global constant names + char *const_name, *const_data_type, *const_primitive, *const_vector, *const_tuple, *const_size, *const_length; + + inline xml_node<>* allocate_append_node(xml_node<>* top, const char* name) + { + xml_node<>* node = xml_doc.allocate_node(node_element, name); + top->append_node(node); + return node; + } + + inline void allocate_append_attribute(xml_node<>* node, const char* attr_name, const char* attr_val) + { + xml_attribute<>* attr = xml_doc.allocate_attribute(attr_name, attr_val); + node->append_attribute(attr); + } + + inline const char* size_to_char(size_t size){ + std::string str = std::to_string(size); + char * writable = new char[str.size() + 1]; + std::copy(str.begin(), str.end(), writable); + writable[str.size()] = '\0'; + return writable; + } + + inline size_t char_to_size(const char* char_size){ + std::istringstream iss(char_size); + size_t size; + iss > size; + return size; + } }; -template -const char* get_smart_type_name() { - std::string str = SmartTypes::get_smart_type_info().name; - char * writable = new char[str.size() + 1]; - std::copy(str.begin(), str.end(), writable); - writable[str.size()] = '\0'; - return writable; -} - //~ } #endif diff --git a/src/forsyde/xml.hpp b/src/forsyde/xml.hpp index 9a7a7ac..dd6b1fd 100644 --- a/src/forsyde/xml.hpp +++ b/src/forsyde/xml.hpp @@ -82,19 +82,41 @@ class XMLExport const_target_port = (char*)"target_port"; const_bound_process = (char*)"bound_process"; const_bound_port = (char*)"bound_port"; + + const_data_type = (char*)"data_type"; } //! The destructor makes sure all XML nodes are deallocated. ~XMLExport() { xml_doc.clear(); + types_doc.clear(); } - //! The traverse function requires the top ForSyDe process name + void traverse(sc_module* top) { + // The top most node for types + types_root = types_doc.allocate_node(node_element, const_data_type); + types_doc.append_node(pn_node); + + this->_traverse(top); + + std::string types_path(path + "types.xml"); + std::ofstream outFile(types_path); + if (!outFile.is_open()) + SC_REPORT_ERROR(types_path.c_str(), "file could not be opened to write the introspection output. Does the path exists?"); + + outFile << "" << std::endl; + outFile << "" << std::endl; + outFile << "" << std::endl; + outFile << types_doc; + } + +private: + //! The _traverse function requires the top ForSyDe process name /*! It initiates the translation job which is a recursive traversal * of the process network. */ - void traverse(sc_module* top) + void _traverse(sc_module* top) { // Initiate the XML file for this level of hierarchy xml_node<>* pn_node = init(top); @@ -119,7 +141,7 @@ class XMLExport add_composite_process(static_cast(*it), pn_node); // Recursion step XMLExport dumper(path); - dumper.traverse(static_cast(*it)); + dumper._traverse(static_cast(*it)); } } else if (is_port(*it)) @@ -266,6 +288,7 @@ class XMLExport xml_node<> *p_node = allocate_append_node(pn_node, const_port); if (port != NULL) { + IntrospectiveType type(types_doc, types_root); allocate_append_attribute(p_node, const_name, dynamic_cast(port)->basename()); allocate_append_attribute(p_node, const_type, port->token_type()); allocate_append_attribute(p_node, const_direction, dir); @@ -294,8 +317,9 @@ class XMLExport SC_REPORT_ERROR("XML Backend", "MoC could not be deduced from kind."); return; } + IntrospectiveType type(types_doc, types_root); allocate_append_attribute(sig_node, const_moc, moc_name); - allocate_append_attribute(sig_node, const_type, sig->token_type()); + allocate_append_attribute(sig_node, const_type, sig->token_type(type)); allocate_append_attribute(sig_node, const_source, sig->oport->get_parent_object()->basename()); allocate_append_attribute(sig_node, const_source_port, sig->oport->basename()); allocate_append_attribute(sig_node, const_target, sig->iport->get_parent_object()->basename()); @@ -331,7 +355,9 @@ class XMLExport std::string path; //! The RapidXML DOM - xml_document<> xml_doc; + xml_document<> xml_doc, types_doc; + xml_node<>* types_root; + //! Some global constant names char *const_name, *const_leaf_process, *const_composite_process, From 9507af23fdbc609aa2d28061859619e001e92341 Mon Sep 17 00:00:00 2001 From: ugeorge Date: Wed, 16 Mar 2016 00:41:06 +0100 Subject: [PATCH 03/18] XML type introspection ready for vector and tuple. Need to devise plan for getting the right sizes --- src/forsyde/abssemantics.hpp | 11 ++- src/forsyde/types.hpp | 156 +++++++++++++++++++++-------------- src/forsyde/xml.hpp | 39 +++------ 3 files changed, 112 insertions(+), 94 deletions(-) diff --git a/src/forsyde/abssemantics.hpp b/src/forsyde/abssemantics.hpp index 7727320..0153383 100644 --- a/src/forsyde/abssemantics.hpp +++ b/src/forsyde/abssemantics.hpp @@ -51,7 +51,7 @@ class introspective_channel { public: //! Name of the tokens in the channels - virtual const char* token_type(IntrospectiveType&) const = 0; + virtual const char* token_type() const = 0; // TODO: remove if proved not to be needed //~ //! Size of the tokens in the channels @@ -89,10 +89,9 @@ class signal: public sc_fifo // TODO: remove if proved not to be needed //! Returns the name of the token type - virtual const char* token_type(IntrospectiveType& type_parser) const + virtual const char* token_type() const { - type_parser.traverse(); - return get_type_name(); + return IntrospectiveType::traverse(); } virtual std::string moc() const = 0; @@ -152,7 +151,7 @@ class in_port: public sc_fifo_in //! Returns the plain name of the token type virtual const char* token_type() const { - return get_type_name(); + return IntrospectiveType::traverse(); } #endif }; @@ -192,7 +191,7 @@ class out_port: public sc_fifo_out //! Returns the name of the actual type (not abst_ext version) virtual const char* token_type() const { - return get_type_name(); + return IntrospectiveType::traverse(); } #endif }; diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index fad7548..94dd2cc 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -1,5 +1,5 @@ /********************************************************************** - * types.hpp -- provides a simple type reflection mechanism. * + * TypeContainer::get().hpp -- provides a simple type reflection mechanism. * * * * Author: Hosein Attarzadeh (shan2@kth.se) based on: * * http://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template * @@ -21,11 +21,11 @@ using namespace rapidxml; -/*! \file types.hpp +/*! \file TypeContainer::get().hpp * \brief Provides facilities for basic type introspection * * This file includes a a set of basic facilities for registering names - * for non-POD C/C++ types to be reflected in the XML output of the + * for non-POD C/C++ TypeContainer::get() to be reflected in the XML output of the * interospection stage. */ @@ -49,11 +49,11 @@ using Tuple = std::tuple; // Specialization for each type #define DEFINE_TYPE(X) \ template<>const char* get_type_name(){return #X;} -// Another version where we explicitly provide the type name (for complex types) +// Another version where we explicitly provide the type name (for complex TypeContainer::get()) #define DEFINE_TYPE_NAME(X,N) \ template<>const char* get_type_name(){return N;} -// Specialization for base types +// Specialization for base TypeContainer::get() DEFINE_TYPE(char); DEFINE_TYPE(short int); @@ -71,61 +71,113 @@ DEFINE_TYPE(long double); DEFINE_TYPE(wchar_t); -class IntrospectiveType { +static char* const_name = (char*)"name"; +static char* const_data_type = (char*)"data_type"; +static char* const_primitive = (char*)"primitive"; +static char* const_vector = (char*)"vector"; +static char* const_tuple = (char*)"tuple"; +static char* const_size = (char*)"size"; +static char* const_length = (char*)"length"; +static char* const_root_type = (char*)"forsyde_types"; + +class TypeContainer { public: - IntrospectiveType(xml_document<>* xml_doc, xml_node<>* root) : xml_doc(xml_doc), root(root) { - const_name = (char*)"name"; - const_data_type = (char*)"data_type"; - const_primitive = (char*)"primitive"; - const_vector = (char*)"vector"; - const_tuple = (char*)"tuple"; - const_size = (char*)"size"; - const_length = (char*)"length"; + static TypeContainer& get() { + static TypeContainer instance; + return instance; } - ~IntrospectiveType(){} + xml_node<>* root() { return root_node; } + xml_document<>* doc() { return &xml_doc; } + + + xml_node<>* add_node(xml_node<>* parent, const char* name) { + xml_node<>* node = xml_doc.allocate_node(node_element, name); + parent->append_node(node); + return node; + } + + void add_attribute(xml_node<>* node, const char* attr_name, const char* attr_val) { + xml_attribute<>* attr = xml_doc.allocate_attribute(attr_name, attr_val); + node->append_attribute(attr); + } + + //! The print method writes the XML file to the output. + /*! The XML structure is already generated, so this command only + * checks for the availability of the output file and dumps the XML + * to it. + */ + void printXML(std::string fileName) + { + std::ofstream outFile(fileName); + if (!outFile.is_open()) + SC_REPORT_ERROR(fileName.c_str(), "file could not be opened to write the introspection output. Does the path exists?"); + outFile << "" << std::endl; + outFile << "" << std::endl; + //outFile << "" << std::endl; + outFile << xml_doc; + + } + +private: + TypeContainer() { + root_node = xml_doc.allocate_node(node_element, const_root_type); + xml_doc.append_node(root_node); + }; + + TypeContainer(TypeContainer const&); + void operator=(TypeContainer const&); + + xml_document<> xml_doc; + xml_node<>* root_node; + +}; + +class IntrospectiveType { public: template - inline void traverse() { - // Get the list of module children (ports and other processes) + static inline const char* traverse() { + xml_node<>* root = TypeContainer::get().root(); + const char* type_name = get_type_name(); for (auto child = root->first_node(); child; child = child->next_sibling()) { - if (child->first_attribute(const_name)->value() == get_type_name() ) return; + if (child->first_attribute(const_name)->value() == type_name ) return type_name; } - xml_node<> *type_node = allocate_append_node(root, const_data_type); - allocate_append_attribute(type_node, const_data_type, get_type_name()); - + xml_node<> *type_node = TypeContainer::get().add_node(root, const_data_type); + TypeContainer::get().add_attribute(type_node, const_name, type_name); add_type_node::get(type_node); + return type_name; }; template struct add_type_node { - inline void get (xml_node<>* parent) { - xml_node<> *primitive_node = allocate_append_node(parent, const_primitive); - allocate_append_attribute(primitive_node, const_name, get_type_name()); - allocate_append_attribute(primitive_node, const_size, size_to_char(sizeof(T))); + static inline void get (xml_node<>* parent) { + xml_node<> *primitive_node = TypeContainer::get().add_node(parent, const_primitive); + TypeContainer::get().add_attribute(primitive_node, const_name, get_type_name()); + TypeContainer::get().add_attribute(primitive_node, const_size, size_to_char(sizeof(T))); } }; template struct add_type_node> { - inline void get (xml_node<>* parent) { - xml_node<> *vector_node = allocate_append_node(parent, const_vector); + static inline void get (xml_node<>* parent) { + xml_node<> *vector_node = TypeContainer::get().add_node(parent, const_vector); + add_type_node::get(vector_node); - size_t child_size = char_to_size(vector_node->first_node()->first_attribute(const_size)->value()); - allocate_append_attribute(vector_node, const_length, size_to_char(sizeof(T)/child_size)); - allocate_append_attribute(vector_node, const_size, size_to_char(sizeof(T))); + //size_t child_size = char_to_size(vector_node->first_node()->first_attribute(const_size)->value()); + //TypeContainer::get().add_attribute(vector_node, const_length, size_to_char(sizeof(T)/child_size)); + TypeContainer::get().add_attribute(vector_node, const_size, size_to_char(sizeof(Vector))); } }; template struct add_type_node> { - inline void get (xml_node<>* parent) { - xml_node<> *tuple_node = allocate_append_node(parent, const_tuple); - traverse_tuple>(tuple_node); - allocate_append_attribute(tuple_node, const_size, size_to_char(sizeof(T))); + static inline void get (xml_node<>* parent) { + xml_node<> *tuple_node = TypeContainer::get().add_node(parent, const_tuple); + traverse_tuple>::get(tuple_node); + //TypeContainer::get().add_attribute(tuple_node, const_size, size_to_char(sizeof(Tuple))); } }; @@ -134,40 +186,20 @@ class IntrospectiveType { template struct traverse_tuple>{ - inline void get (xml_node<>* parent) { - add_type_node(parent); - traverse_tuple>(parent); + static inline void get (xml_node<>* parent) { + add_type_node::get(parent); + traverse_tuple>::get(parent); } }; template struct traverse_tuple<1, Tuple> { - inline void get (xml_node<>* parent) { - add_type_node(parent); + static inline void get (xml_node<>* parent) { + add_type_node::get(parent); } }; - //! The RapidXML DOM - xml_document<>* xml_doc; - xml_node<>* root; - - //! Some global constant names - char *const_name, *const_data_type, *const_primitive, *const_vector, *const_tuple, *const_size, *const_length; - - inline xml_node<>* allocate_append_node(xml_node<>* top, const char* name) - { - xml_node<>* node = xml_doc.allocate_node(node_element, name); - top->append_node(node); - return node; - } - - inline void allocate_append_attribute(xml_node<>* node, const char* attr_name, const char* attr_val) - { - xml_attribute<>* attr = xml_doc.allocate_attribute(attr_name, attr_val); - node->append_attribute(attr); - } - - inline const char* size_to_char(size_t size){ + static inline const char* size_to_char(size_t size){ std::string str = std::to_string(size); char * writable = new char[str.size() + 1]; std::copy(str.begin(), str.end(), writable); @@ -175,10 +207,10 @@ class IntrospectiveType { return writable; } - inline size_t char_to_size(const char* char_size){ + static inline size_t char_to_size(const char* char_size){ std::istringstream iss(char_size); size_t size; - iss > size; + iss >> size; return size; } }; diff --git a/src/forsyde/xml.hpp b/src/forsyde/xml.hpp index dd6b1fd..add661b 100644 --- a/src/forsyde/xml.hpp +++ b/src/forsyde/xml.hpp @@ -23,6 +23,7 @@ */ #include +#include #include "rapidxml_print.hpp" #include "abssemantics.hpp" @@ -42,6 +43,7 @@ void get_moc_and_pc(const std::string& kind, std::string& moc, std::string& pc) pc = kind.substr(kind.rfind(':')+1, kind.length()); } + //! Abstract class used to Export a system as an XML file /*! This class provides basic facilities to export a ForSyDe-SystemC * process network as an XML file. @@ -82,45 +84,33 @@ class XMLExport const_target_port = (char*)"target_port"; const_bound_process = (char*)"bound_process"; const_bound_port = (char*)"bound_port"; - - const_data_type = (char*)"data_type"; } //! The destructor makes sure all XML nodes are deallocated. ~XMLExport() { xml_doc.clear(); - types_doc.clear(); } void traverse(sc_module* top) { - // The top most node for types - types_root = types_doc.allocate_node(node_element, const_data_type); - types_doc.append_node(pn_node); - this->_traverse(top); - std::string types_path(path + "types.xml"); - std::ofstream outFile(types_path); - if (!outFile.is_open()) - SC_REPORT_ERROR(types_path.c_str(), "file could not be opened to write the introspection output. Does the path exists?"); - - outFile << "" << std::endl; - outFile << "" << std::endl; - outFile << "" << std::endl; - outFile << types_doc; + TypeContainer::get().printXML(types_path); } -private: //! The _traverse function requires the top ForSyDe process name /*! It initiates the translation job which is a recursive traversal * of the process network. */ + +private: + void _traverse(sc_module* top) { // Initiate the XML file for this level of hierarchy xml_node<>* pn_node = init(top); - + std::cout<<"parsing " << pn_node->name(); + // Get the list of module children (ports and other processes) std::vector children = top->get_child_objects(); @@ -167,7 +157,7 @@ class XMLExport printXML(path + name_str + std::string(".xml")); } - + //! The init member initiates the XML DOM and performs initial settings. /*! */ @@ -186,7 +176,7 @@ class XMLExport return pn_node; } - + //! The print method writes the XML file to the output. /*! The XML structure is already generated, so this command only * checks for the availability of the output file and dumps the XML @@ -288,7 +278,6 @@ class XMLExport xml_node<> *p_node = allocate_append_node(pn_node, const_port); if (port != NULL) { - IntrospectiveType type(types_doc, types_root); allocate_append_attribute(p_node, const_name, dynamic_cast(port)->basename()); allocate_append_attribute(p_node, const_type, port->token_type()); allocate_append_attribute(p_node, const_direction, dir); @@ -317,9 +306,8 @@ class XMLExport SC_REPORT_ERROR("XML Backend", "MoC could not be deduced from kind."); return; } - IntrospectiveType type(types_doc, types_root); allocate_append_attribute(sig_node, const_moc, moc_name); - allocate_append_attribute(sig_node, const_type, sig->token_type(type)); + allocate_append_attribute(sig_node, const_type, sig->token_type()); allocate_append_attribute(sig_node, const_source, sig->oport->get_parent_object()->basename()); allocate_append_attribute(sig_node, const_source_port, sig->oport->basename()); allocate_append_attribute(sig_node, const_target, sig->iport->get_parent_object()->basename()); @@ -355,8 +343,7 @@ class XMLExport std::string path; //! The RapidXML DOM - xml_document<> xml_doc, types_doc; - xml_node<>* types_root; + xml_document<> xml_doc; //! Some global constant names @@ -367,7 +354,7 @@ class XMLExport *const_port_dir, *const_direction, *const_in, *const_out, *const_signal, *const_component_name, *const_argument, *const_value, *const_source, *const_source_port, *const_target, *const_target_port, - *const_bound_process, *const_bound_port; + *const_bound_process, *const_bound_port, *const_data_type; inline xml_node<>* allocate_append_node(xml_node<>* top, const char* name) { From c440cbc0b36cb907eb7d372d5cfe5262ef99ef37 Mon Sep 17 00:00:00 2001 From: ugeorge Date: Wed, 16 Mar 2016 16:11:42 +0100 Subject: [PATCH 04/18] Finished implementing type introspection for basic template types. First tests look promising. --- src/forsyde/sdf_process_constructors.hpp | 2 +- src/forsyde/types.hpp | 173 +++++++++++++++++------ src/forsyde/xml.hpp | 15 +- 3 files changed, 137 insertions(+), 53 deletions(-) diff --git a/src/forsyde/sdf_process_constructors.hpp b/src/forsyde/sdf_process_constructors.hpp index 4cccb83..dd3a39c 100644 --- a/src/forsyde/sdf_process_constructors.hpp +++ b/src/forsyde/sdf_process_constructors.hpp @@ -1168,7 +1168,7 @@ class zip : public sdf_process for (auto i=0; i #include #include "rapidxml_print.hpp" @@ -21,40 +43,42 @@ using namespace rapidxml; -/*! \file TypeContainer::get().hpp - * \brief Provides facilities for basic type introspection - * - * This file includes a a set of basic facilities for registering names - * for non-POD C/C++ TypeContainer::get() to be reflected in the XML output of the - * interospection stage. - */ - -//~ namespace ForSyDe -//~ { - - // The general case uses RTTI (if the type is not registered explicitly) #pragma once template const char* get_type_name() { return typeid(T).name(); } - -template -using Vector = std::vector; - -template -using Tuple = std::tuple; - // Specialization for each type #define DEFINE_TYPE(X) \ template<>const char* get_type_name(){return #X;} -// Another version where we explicitly provide the type name (for complex TypeContainer::get()) + +// Another version where we explicitly provide the type name (for complex types) #define DEFINE_TYPE_NAME(X,N) \ template<>const char* get_type_name(){return N;} -// Specialization for base TypeContainer::get() +// Defines also the streaming operator for user defined types. Must be followed by a function definition. {} +#define DEFINE_TYPE_NAME_STREAM(X, N) \ + DEFINE_TYPE_NAME(X, N); \ + void getCustomTypeDefinition(std::ostream &os, const X &obj); \ + std::ostream& operator <<(std::ostream &os, const X &obj) \ + { \ + getCustomTypeDefinition(os, obj); \ + return os;\ + } \ + void getCustomTypeDefinition(std::ostream &os, const X &obj) + +// Helper macro for creating structures. Must be followed by a definition between {} +#define STRUCT(NAME, DEF)\ + typedef struct NAME { \ + DEF \ + } NAME; \ + DEFINE_TYPE_NAME_STREAM(NAME, #NAME) {} + + + +// Primitive type name definition DEFINE_TYPE(char); DEFINE_TYPE(short int); DEFINE_TYPE(unsigned short int); @@ -71,32 +95,64 @@ DEFINE_TYPE(long double); DEFINE_TYPE(wchar_t); + +namespace ForSyDe +{ + +// Identifiers for primitive types +template struct isPrimitive { enum { val = 0 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; +template<> struct isPrimitive { enum { val = 1 }; }; + +// xml label names static char* const_name = (char*)"name"; static char* const_data_type = (char*)"data_type"; static char* const_primitive = (char*)"primitive"; +static char* const_custom = (char*)"custom"; static char* const_vector = (char*)"vector"; +static char* const_array = (char*)"array"; static char* const_tuple = (char*)"tuple"; static char* const_size = (char*)"size"; static char* const_length = (char*)"length"; static char* const_root_type = (char*)"forsyde_types"; + +//! Singleton container for storing type structures during introspection +/*! This class is used to store type structures during the introspection phase + * as XML DOM document. It identifies types from the ForSyDe-IR by their + * name given by the RTTI and stores them only once. + */ class TypeContainer { public: + //! The instance getter. static TypeContainer& get() { static TypeContainer instance; return instance; } + //! Returns the root node of the XML DOM xml_node<>* root() { return root_node; } - xml_document<>* doc() { return &xml_doc; } - + //! Allocates and appends a node to the XML documents, and returns its pointer. xml_node<>* add_node(xml_node<>* parent, const char* name) { xml_node<>* node = xml_doc.allocate_node(node_element, name); parent->append_node(node); return node; } + //! Allocates and appends an attribute to an XML node, and returns its pointer. void add_attribute(xml_node<>* node, const char* attr_name, const char* attr_val) { xml_attribute<>* attr = xml_doc.allocate_attribute(attr_name, attr_val); node->append_attribute(attr); @@ -120,26 +176,45 @@ class TypeContainer { } private: + //! The (hidden) default constructor. TypeContainer() { root_node = xml_doc.allocate_node(node_element, const_root_type); xml_doc.append_node(root_node); }; + // these are needed to ensure singleton pattern TypeContainer(TypeContainer const&); void operator=(TypeContainer const&); + //! The RapidXML DOM xml_document<> xml_doc; + + //! The root node xml_node<>* root_node; }; +//! Class containing methods for recursive type introspection +/*! This class is used as a namespace for all template functions used for + * recursive type introspection. During the traversal of a type, its structure + * is being stored in a TypeContainer singleton. + */ class IntrospectiveType { public: + //! Main (and only) function for parsing a data type + /*! This function is the only one called during the introspection phase to + * traverse a type. + * + * If the FORSYDE_TYPE_INTROSPECTION compiler flag is enabled then it + * updates the TypeContainer with the XML structure extracted. Otherwise + * it just returns its identifier (RTTI or given name). + */ template static inline const char* traverse() { - xml_node<>* root = TypeContainer::get().root(); const char* type_name = get_type_name(); +#ifdef FORSYDE_TYPE_INTROSPECTION + xml_node<>* root = TypeContainer::get().root(); for (auto child = root->first_node(); child; child = child->next_sibling()) { if (child->first_attribute(const_name)->value() == type_name ) return type_name; } @@ -147,58 +222,73 @@ class IntrospectiveType { xml_node<> *type_node = TypeContainer::get().add_node(root, const_data_type); TypeContainer::get().add_attribute(type_node, const_name, type_name); add_type_node::get(type_node); +#endif return type_name; }; + // Default template for getting the information of a node, in case no other structure is identified template struct add_type_node { static inline void get (xml_node<>* parent) { - xml_node<> *primitive_node = TypeContainer::get().add_node(parent, const_primitive); + char* node_type = (isPrimitive::val) ? const_primitive : const_custom; + xml_node<> *primitive_node = TypeContainer::get().add_node(parent, node_type); TypeContainer::get().add_attribute(primitive_node, const_name, get_type_name()); TypeContainer::get().add_attribute(primitive_node, const_size, size_to_char(sizeof(T))); } }; + // Template specialization for parsing vectors template - struct add_type_node> { + struct add_type_node> { static inline void get (xml_node<>* parent) { xml_node<> *vector_node = TypeContainer::get().add_node(parent, const_vector); add_type_node::get(vector_node); + } + }; - //size_t child_size = char_to_size(vector_node->first_node()->first_attribute(const_size)->value()); - //TypeContainer::get().add_attribute(vector_node, const_length, size_to_char(sizeof(T)/child_size)); - TypeContainer::get().add_attribute(vector_node, const_size, size_to_char(sizeof(Vector))); + // Template specialization for parsing fixed size (std::)arrays + template + struct add_type_node> { + static inline void get (xml_node<>* parent) { + xml_node<> *vector_node = TypeContainer::get().add_node(parent, const_array); + TypeContainer::get().add_attribute(vector_node, const_length, size_to_char(S)); + + add_type_node::get(vector_node); } }; + // Template specialization for parsing tuples template - struct add_type_node> { + struct add_type_node> { static inline void get (xml_node<>* parent) { xml_node<> *tuple_node = TypeContainer::get().add_node(parent, const_tuple); - traverse_tuple>::get(tuple_node); - //TypeContainer::get().add_attribute(tuple_node, const_size, size_to_char(sizeof(Tuple))); + traverse_tuple>::get(tuple_node); } }; + // Default template for traversing a tuple template struct traverse_tuple {}; + // Template specialization for traversing a tuple with multiple elements template - struct traverse_tuple>{ + struct traverse_tuple>{ static inline void get (xml_node<>* parent) { add_type_node::get(parent); - traverse_tuple>::get(parent); + traverse_tuple>::get(parent); } }; + // Template specialization for traversing a tuple with one element template - struct traverse_tuple<1, Tuple> { + struct traverse_tuple<1, std::tuple> { static inline void get (xml_node<>* parent) { add_type_node::get(parent); } }; + // Utility function : size_t to char array static inline const char* size_to_char(size_t size){ std::string str = std::to_string(size); char * writable = new char[str.size() + 1]; @@ -207,6 +297,7 @@ class IntrospectiveType { return writable; } + // Utility function : char array size_t static inline size_t char_to_size(const char* char_size){ std::istringstream iss(char_size); size_t size; @@ -215,6 +306,6 @@ class IntrospectiveType { } }; -//~ } +} #endif diff --git a/src/forsyde/xml.hpp b/src/forsyde/xml.hpp index add661b..8f416bd 100644 --- a/src/forsyde/xml.hpp +++ b/src/forsyde/xml.hpp @@ -92,20 +92,12 @@ class XMLExport xml_doc.clear(); } - void traverse(sc_module* top) { - this->_traverse(top); - std::string types_path(path + "types.xml"); - TypeContainer::get().printXML(types_path); - } - - //! The _traverse function requires the top ForSyDe process name + //! The traverse function requires the top ForSyDe process name /*! It initiates the translation job which is a recursive traversal * of the process network. */ -private: - - void _traverse(sc_module* top) + void traverse(sc_module* top) { // Initiate the XML file for this level of hierarchy xml_node<>* pn_node = init(top); @@ -131,7 +123,7 @@ class XMLExport add_composite_process(static_cast(*it), pn_node); // Recursion step XMLExport dumper(path); - dumper._traverse(static_cast(*it)); + dumper.traverse(static_cast(*it)); } } else if (is_port(*it)) @@ -158,6 +150,7 @@ class XMLExport } +private: //! The init member initiates the XML DOM and performs initial settings. /*! */ From 9bf91c39fd0c82a28e3da76949b4e9b76942cfb6 Mon Sep 17 00:00:00 2001 From: ugeorge Date: Thu, 17 Mar 2016 13:05:57 +0100 Subject: [PATCH 05/18] type helper macros --- src/forsyde/types.hpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index 77998be..2dde430 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -43,23 +43,38 @@ using namespace rapidxml; +template +using token_tuple_t = std::tuple...>; + +template +using token_t = std::vector; + // The general case uses RTTI (if the type is not registered explicitly) #pragma once template const char* get_type_name() { return typeid(T).name(); } +// helper macros +#define FIRST_ARG___(N, ...) N +#define FARG_NAME___(N, ...) #N +#define REST_ARGS___(N, ...) __VA_ARGS__ +#define FIRST_ARG__(args) FIRST_ARG___ args +#define FARG_NAME__(args) FARG_NAME___ args +#define REST_ARGS__(args) REST_ARGS___ args + + // Specialization for each type #define DEFINE_TYPE(X) \ template<>const char* get_type_name(){return #X;} -// Another version where we explicitly provide the type name (for complex types) -#define DEFINE_TYPE_NAME(X,N) \ - template<>const char* get_type_name(){return N;} +#define DEFINE_TYPE_NAME(X, N) \ + template<>const char* get_type_name(){return N;} + // Defines also the streaming operator for user defined types. Must be followed by a function definition. {} -#define DEFINE_TYPE_NAME_STREAM(X, N) \ - DEFINE_TYPE_NAME(X, N); \ +#define DEFINE_TYPE_STREAM(X) \ + DEFINE_TYPE(X); \ void getCustomTypeDefinition(std::ostream &os, const X &obj); \ std::ostream& operator <<(std::ostream &os, const X &obj) \ { \ @@ -69,11 +84,11 @@ template const char* get_type_name() { void getCustomTypeDefinition(std::ostream &os, const X &obj) // Helper macro for creating structures. Must be followed by a definition between {} -#define STRUCT(NAME, DEF)\ - typedef struct NAME { \ - DEF \ - } NAME; \ - DEFINE_TYPE_NAME_STREAM(NAME, #NAME) {} +#define STRUCT(...)\ + typedef struct FIRST_ARG__((__VA_ARGS__)) { \ + REST_ARGS__((__VA_ARGS__)) \ + } FIRST_ARG__((__VA_ARGS__)); \ + DEFINE_TYPE_STREAM(FIRST_ARG__((__VA_ARGS__))) From 107af560d1ffd6e53208b6c0045bb2817a16d30c Mon Sep 17 00:00:00 2001 From: ugeorge Date: Fri, 18 Mar 2016 17:32:10 +0100 Subject: [PATCH 06/18] first attempt to provide token_tuple_t --- src/forsyde.hpp | 2 - src/forsyde/types.hpp | 128 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 117 insertions(+), 13 deletions(-) diff --git a/src/forsyde.hpp b/src/forsyde.hpp index f28d39e..91bebb7 100644 --- a/src/forsyde.hpp +++ b/src/forsyde.hpp @@ -69,9 +69,7 @@ // include the main SystemC library #include -#ifdef FORSYDE_INTROSPECTION #include "forsyde/types.hpp" -#endif // include the abstract semantics #include "forsyde/abssemantics.hpp" diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index 2dde430..626d3a6 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -15,8 +15,8 @@ * License: * *******************************************************************/ -#ifndef TYPES_HPP -#define TYPES_HPP +#ifndef FORSYDE_TYPES_HPP +#define FORSYDE_TYPES_HPP /*! \file types.hpp * \brief Provides facilities for type introspection @@ -41,13 +41,12 @@ #include "rapidxml_print.hpp" -using namespace rapidxml; +#include +#include +#include -template -using token_tuple_t = std::tuple...>; -template -using token_t = std::vector; +using namespace rapidxml; // The general case uses RTTI (if the type is not registered explicitly) #pragma once @@ -65,11 +64,11 @@ template const char* get_type_name() { // Specialization for each type -#define DEFINE_TYPE(X) \ - template<>const char* get_type_name(){return #X;} +#define DEFINE_TYPE(...) \ + template<>const char* get_type_name<__VA_ARGS__>(){return #__VA_ARGS__;} -#define DEFINE_TYPE_NAME(X, N) \ - template<>const char* get_type_name(){return N;} +#define DEFINE_TYPE_NAME(...) \ + template<>const char* get_type_name(){return FIRST_ARG__((__VA_ARGS__);} // Defines also the streaming operator for user defined types. Must be followed by a function definition. {} @@ -83,6 +82,19 @@ template const char* get_type_name() { } \ void getCustomTypeDefinition(std::ostream &os, const X &obj) + +#define TYPEDEF(...)\ + typedef REST_ARGS__((__VA_ARGS__)) FIRST_ARG__((__VA_ARGS__));\ + DEFINE_TYPE(FIRST_ARG__((__VA_ARGS__))) + +// Helper macro for creating C structures. Must be followed by a definition between {} +#define C_STRUCT(...)\ + extern "C" typedef struct FIRST_ARG__((__VA_ARGS__)) { \ + REST_ARGS__((__VA_ARGS__)) \ + } FIRST_ARG__((__VA_ARGS__)); \ + DEFINE_TYPE_STREAM(FIRST_ARG__((__VA_ARGS__))) + + // Helper macro for creating structures. Must be followed by a definition between {} #define STRUCT(...)\ typedef struct FIRST_ARG__((__VA_ARGS__)) { \ @@ -91,7 +103,19 @@ template const char* get_type_name() { DEFINE_TYPE_STREAM(FIRST_ARG__((__VA_ARGS__))) +// Helper macro for creating unions. Must be followed by a definition between {} +#define UNION(...)\ + typedef union FIRST_ARG__((__VA_ARGS__)) { \ + REST_ARGS__((__VA_ARGS__)) \ + } FIRST_ARG__((__VA_ARGS__)); \ + DEFINE_TYPE_STREAM(FIRST_ARG__((__VA_ARGS__))) +// Helper macro for creating C unions. Must be followed by a definition between {} +#define C_UNION(...)\ + extern "C" typedef union FIRST_ARG__((__VA_ARGS__)) { \ + REST_ARGS__((__VA_ARGS__)) \ + } FIRST_ARG__((__VA_ARGS__)); \ + DEFINE_TYPE_STREAM(FIRST_ARG__((__VA_ARGS__))) // Primitive type name definition DEFINE_TYPE(char); @@ -111,9 +135,84 @@ DEFINE_TYPE(wchar_t); + +template +using token_t = std::vector; + +template +using token_tuple_t = std::tuple...>; + namespace ForSyDe { + +template +struct token_tuple_t_ +{ + typedef std::tuple...> tupvec; + tupvec t; + + token_tuple_t_(std::initializer_list list) { + traverse_tuple::resize(list.end(), t); + } + + void resize(std::initializer_list list) { + traverse_tuple::resize(list.end(), t); + } + + /*template + T& get(size_t n_token) { return std::get(t)[n_token]; }*/ + + + explicit token_tuple_t_(const std::tuple...> t_) : t(t_) {}; + token_tuple_t_(const token_tuple_t_ & t_) : t(t_.t){} + token_tuple_t_ & operator=(const token_tuple_t_ & rhs) { t = rhs.t; return *this;} + token_tuple_t_ & operator=(const std::tuple...> & rhs) { t = rhs; return *this;} + operator const std::tuple...> & () const {return t; } + operator std::tuple...> & () { return t; } + bool operator==(const token_tuple_t_ & rhs) const { return t == rhs.t; } + bool operator<(const token_tuple_t_ & rhs) const { return t < rhs.t; } + + +private: + // Default template for traversing a tuple + template + struct traverse_tuple {}; + + // Template specialization for traversing a tuple with multiple elements + template + struct traverse_tuple>{ + static inline void resize(std::initializer_list::iterator size, tupvec tv) { + std::get(tv).resize(*size); + traverse_tuple>::resize(size--, tv); + } + }; + + // Template specialization for traversing a tuple with one element + template + struct traverse_tuple<1, std::tuple> { + static inline void resize(std::initializer_list::iterator size, tupvec tv) { + std::get<1>(tv).resize(*size); + } + }; + +}; + + + +/* D(){}; \ + D(const D & t_) : t(t_.t){} \ + D & operator=(const D & rhs) { t = rhs.t; return *this;} \ + D & operator=(const T & rhs) { t = rhs; return *this;} \ + operator const T & () const {return t; } \ + operator T & () { return t; } \ + bool operator==(const D & rhs) const { return t == rhs.t; } \ + bool operator<(const D & rhs) const { return t < rhs.t; } \*/ + + + +#ifdef FORSYDE_TYPE_INTROSPECTION + // Identifiers for primitive types template struct isPrimitive { enum { val = 0 }; }; template<> struct isPrimitive { enum { val = 1 }; }; @@ -209,6 +308,8 @@ class TypeContainer { }; +#endif + //! Class containing methods for recursive type introspection /*! This class is used as a namespace for all template functions used for * recursive type introspection. During the traversal of a type, its structure @@ -241,6 +342,8 @@ class IntrospectiveType { return type_name; }; +#ifdef FORSYDE_TYPE_INTROSPECTION + // Default template for getting the information of a node, in case no other structure is identified template struct add_type_node { @@ -278,6 +381,7 @@ class IntrospectiveType { struct add_type_node> { static inline void get (xml_node<>* parent) { xml_node<> *tuple_node = TypeContainer::get().add_node(parent, const_tuple); + TypeContainer::get().add_attribute(tuple_node, const_length, size_to_char(sizeof...(T))); traverse_tuple>::get(tuple_node); } }; @@ -319,6 +423,8 @@ class IntrospectiveType { iss >> size; return size; } + +#endif }; } From 542f39cede8114d59110fe6330bf3439a23e839e Mon Sep 17 00:00:00 2001 From: ugeorge Date: Sat, 19 Mar 2016 23:34:29 +0100 Subject: [PATCH 07/18] testing token_tuple. Will proceed with the cleaner but more distruprive solution of renaming vector to tokens in branch type-introspection --- src/forsyde/sdf_moc.hpp | 1 + src/forsyde/sdf_process_constructors.hpp | 30 +++-- src/forsyde/sdf_types.hpp | 138 +++++++++++++++++++++++ src/forsyde/types.hpp | 126 +++++++-------------- 4 files changed, 191 insertions(+), 104 deletions(-) create mode 100644 src/forsyde/sdf_types.hpp diff --git a/src/forsyde/sdf_moc.hpp b/src/forsyde/sdf_moc.hpp index 9ee4750..b158bed 100644 --- a/src/forsyde/sdf_moc.hpp +++ b/src/forsyde/sdf_moc.hpp @@ -27,6 +27,7 @@ #include "sdf_process.hpp" #include "sdf_process_constructors.hpp" #include "sdf_helpers.hpp" +#include "sdf_types.hpp" namespace ForSyDe { diff --git a/src/forsyde/sdf_process_constructors.hpp b/src/forsyde/sdf_process_constructors.hpp index dd3a39c..6ce1f97 100644 --- a/src/forsyde/sdf_process_constructors.hpp +++ b/src/forsyde/sdf_process_constructors.hpp @@ -1128,7 +1128,7 @@ class zip : public sdf_process public: SDF_in iport1; ///< port for the input channel 1 SDF_in iport2; ///< port for the input channel 2 - SDF_out,std::vector>> oport1;///< port for the output channel + SDF_out> oport1;///< port for the output channel //! The constructor requires the module name /*! It creates an SC_THREAD which reads data from its input ports, @@ -1153,29 +1153,27 @@ class zip : public sdf_process unsigned i1toks; unsigned i2toks; - // intermediate values - std::vector ival1; - std::vector ival2; + token_tuple ival; + void init() { - ival1.resize(i1toks); - ival2.resize(i2toks); + ival.resize({i1toks, i2toks}); } void prep() { for (auto i=0; i(i) = iport1.read(); for (auto i=0; i(i) = iport2.read(); } void exec() {} void prod() { - WRITE_MULTIPORT(oport1,std::make_tuple(ival1,ival2)) // write to the output + WRITE_MULTIPORT(oport1,ival) // write to the output } void clean() {} @@ -1200,7 +1198,7 @@ class zipN : public sdf_process { public: std::tuple ...> iport;///< tuple of ports for the input channels - SDF_out...> > oport1;///< port for the output channel + SDF_out > oport1;///< port for the output channel //! The constructor requires the module name /*! It creates an SC_THREAD which reads data from its input port, @@ -1224,11 +1222,11 @@ class zipN : public sdf_process private: std::vector in_toks; // intermediate values - std::tuple...>* in_val; + token_tuple* in_val; void init() { - in_val = new std::tuple...>; + in_val = new token_tuple; } void prep() @@ -1326,7 +1324,7 @@ template class unzip : public sdf_process { public: - SDF_in,std::vector>> iport1;///< port for the input channel + SDF_in> iport1;///< port for the input channel SDF_out oport1; ///< port for the output channel 1 SDF_out oport2; ///< port for the output channel 2 @@ -1363,7 +1361,7 @@ class unzip : public sdf_process void prep() { - *in_val = iport1.read(); + *in_val = iport1.read().t; } void exec() {} @@ -1399,7 +1397,7 @@ template class unzipN : public sdf_process { public: - SDF_in...>> iport1;///< port for the input channel + SDF_in> iport1;///< port for the input channel std::tuple...> oport;///< tuple of ports for the output channels //! The constructor requires the module name @@ -1433,7 +1431,7 @@ class unzipN : public sdf_process void prep() { - *in_val = iport1.read(); + *in_val = iport1.read().t; } void exec() {} diff --git a/src/forsyde/sdf_types.hpp b/src/forsyde/sdf_types.hpp new file mode 100644 index 0000000..0948f73 --- /dev/null +++ b/src/forsyde/sdf_types.hpp @@ -0,0 +1,138 @@ +/********************************************************************** + * sdf_types.hpp -- Specific types for the SDF MoC * + * * + * Author: George Ungureanu (ugeorge@kth.se) * + * * + * Purpose: Providing promitive element required for modeling * + * synchronous dataflow systems in ForSyDe-SystemC * + * * + * Usage: This file is included automatically * + * * + * License: BSD3 * + *******************************************************************/ + +#ifndef SDF_TYPES_HPP +#define SDF_TYPES_HPP + +/*! \file sdf_moc.hpp + * \brief Implements the Synchronous Dataflow (SDF) Model of Computation + * + * This file includes the basic process constructors and other + * facilities used for modeling in the SDF model of computation. + */ + +#include +#include +#include + + +namespace ForSyDe { + +namespace SDF { + + +template +using tokens = std::vector; + + +template +struct token_tuple { + typedef std::tuple...> type; + + type t; + + token_tuple() {} + + token_tuple(std::initializer_list list) { + traverse_tuple::resize(list.end(), t); + } + + void resize(std::initializer_list list) { + traverse_tuple::resize(list.end(), t); + } + + template< std::size_t I, std::size_t N > + auto get() { return std::get(t)[N]; } + + template< std::size_t I> + auto get(size_t n) { return std::get(t)[n]; } + + explicit token_tuple(const std::tuple...> t_) : t(t_) {}; + token_tuple(const token_tuple & t_) : t(t_.t){} + token_tuple& operator=(const token_tuple& rhs) { t = rhs.t; return *this;} + token_tuple& operator=(const std::tuple...>& rhs) { t = rhs; return *this;} + + /*operator const std::tuple...> & () const {return t; } + operator std::tuple...> & () { return t; } + bool operator==(const token_tuple & rhs) const { return t == rhs.t; } + bool operator<(const token_tuple & rhs) const { return t < rhs.t; }*/ + +private: + + // Default template for traversing a tuple + template + struct traverse_tuple {}; + + // Template specialization for traversing a tuple with multiple elements + template + struct traverse_tuple, Tail...>>{ + static inline void resize(std::initializer_list::iterator size, std::tuple, Tail...> tv) { + --size; + std::get(tv).resize(*size); + traverse_tuple, Tail...>>::resize(size, tv); + } + }; + + // Template specialization for traversing a tuple with one element + template + struct traverse_tuple<1, std::tuple, Tail...>>{ + static inline void resize(std::initializer_list::iterator size, std::tuple, Tail...> tv) { + std::get<0>(tv).resize(*size); + } + }; + +}; + +template +std::ostream& operator <<(std::ostream &os, const token_tuple &obj) { + return os; +} + + +template +tokens init(size_t n){ + return tokens(n); +} +template +void resize(size_t n, tokens v){ + return v.resize(n); +} +template +T& get(tokens v){ + return v.at(N); +} + +template +tokens> init(size_t n, std::initializer_list list){ + return tokens>(n, token_tuple(list)); +} +template +void resize(size_t n, std::initializer_list list, tokens> v ){ + return v.resize(n); +} +template< std::size_t N1, std::size_t N2, std::size_t N3, typename... T > +auto get(tokens> v) { + return v[N1].get(); +} +template< std::size_t N1, std::size_t N2, typename... T > +auto get_tokens(tokens> v) { + return std::get(v[N1].t); +} + + +} +} + +#endif + + diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index 626d3a6..3a80655 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -34,16 +34,12 @@ */ - - #include - #include -#include "rapidxml_print.hpp" +#include +#include - -#include -#include -#include +#include "rapidxml_print.hpp" +#include "sdf_types.hpp" using namespace rapidxml; @@ -72,15 +68,15 @@ template const char* get_type_name() { // Defines also the streaming operator for user defined types. Must be followed by a function definition. {} -#define DEFINE_TYPE_STREAM(X) \ - DEFINE_TYPE(X); \ - void getCustomTypeDefinition(std::ostream &os, const X &obj); \ - std::ostream& operator <<(std::ostream &os, const X &obj) \ +#define DEFINE_TYPE_STREAM(...) \ + DEFINE_TYPE(__VA_ARGS__); \ + void getCustomTypeDefinition(std::ostream &os, const __VA_ARGS__ &obj); \ + std::ostream& operator <<(std::ostream &os, const __VA_ARGS__ &obj) \ { \ getCustomTypeDefinition(os, obj); \ return os;\ } \ - void getCustomTypeDefinition(std::ostream &os, const X &obj) + void getCustomTypeDefinition(std::ostream &os, const __VA_ARGS__ &obj) #define TYPEDEF(...)\ @@ -133,84 +129,9 @@ DEFINE_TYPE(double); DEFINE_TYPE(long double); DEFINE_TYPE(wchar_t); - - - -template -using token_t = std::vector; - -template -using token_tuple_t = std::tuple...>; - namespace ForSyDe { - -template -struct token_tuple_t_ -{ - typedef std::tuple...> tupvec; - tupvec t; - - token_tuple_t_(std::initializer_list list) { - traverse_tuple::resize(list.end(), t); - } - - void resize(std::initializer_list list) { - traverse_tuple::resize(list.end(), t); - } - - /*template - T& get(size_t n_token) { return std::get(t)[n_token]; }*/ - - - explicit token_tuple_t_(const std::tuple...> t_) : t(t_) {}; - token_tuple_t_(const token_tuple_t_ & t_) : t(t_.t){} - token_tuple_t_ & operator=(const token_tuple_t_ & rhs) { t = rhs.t; return *this;} - token_tuple_t_ & operator=(const std::tuple...> & rhs) { t = rhs; return *this;} - operator const std::tuple...> & () const {return t; } - operator std::tuple...> & () { return t; } - bool operator==(const token_tuple_t_ & rhs) const { return t == rhs.t; } - bool operator<(const token_tuple_t_ & rhs) const { return t < rhs.t; } - - -private: - // Default template for traversing a tuple - template - struct traverse_tuple {}; - - // Template specialization for traversing a tuple with multiple elements - template - struct traverse_tuple>{ - static inline void resize(std::initializer_list::iterator size, tupvec tv) { - std::get(tv).resize(*size); - traverse_tuple>::resize(size--, tv); - } - }; - - // Template specialization for traversing a tuple with one element - template - struct traverse_tuple<1, std::tuple> { - static inline void resize(std::initializer_list::iterator size, tupvec tv) { - std::get<1>(tv).resize(*size); - } - }; - -}; - - - -/* D(){}; \ - D(const D & t_) : t(t_.t){} \ - D & operator=(const D & rhs) { t = rhs.t; return *this;} \ - D & operator=(const T & rhs) { t = rhs; return *this;} \ - operator const T & () const {return t; } \ - operator T & () { return t; } \ - bool operator==(const D & rhs) const { return t == rhs.t; } \ - bool operator<(const D & rhs) const { return t < rhs.t; } \*/ - - - #ifdef FORSYDE_TYPE_INTROSPECTION // Identifiers for primitive types @@ -386,6 +307,16 @@ class IntrospectiveType { } }; + // Template specialization for parsing tuples + template + struct add_type_node> { + static inline void get (xml_node<>* parent) { + xml_node<> *tuple_node = TypeContainer::get().add_node(parent, const_tuple); + TypeContainer::get().add_attribute(tuple_node, const_length, size_to_char(sizeof...(T))); + traverse_tuple>::get(tuple_node); + } + }; + // Default template for traversing a tuple template struct traverse_tuple {}; @@ -407,6 +338,25 @@ class IntrospectiveType { } }; + // Template specialization for traversing a tuple with multiple elements + template + struct traverse_tuple>{ + static inline void get (xml_node<>* parent) { + add_type_node::get(parent); + traverse_tuple>::get(parent); + } + }; + + // Template specialization for traversing a tuple with one element + template + struct traverse_tuple<1, SDF::token_tuple> { + static inline void get (xml_node<>* parent) { + add_type_node::get(parent); + } + }; + + + // Utility function : size_t to char array static inline const char* size_to_char(size_t size){ std::string str = std::to_string(size); From 0677f16145f3792a8815d1461c9e15079fa028e0 Mon Sep 17 00:00:00 2001 From: ugeorge Date: Mon, 21 Mar 2016 00:14:58 +0100 Subject: [PATCH 08/18] debugged access helpers. Tried recursive implementation but GCC breaks. Until further notice, overloading works just fine. --- src/forsyde/sdf_process_constructors.hpp | 12 ++-- src/forsyde/sdf_types.hpp | 88 +++++++++++++++++++----- src/forsyde/types.hpp | 4 ++ src/forsyde/xml.hpp | 1 - 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/src/forsyde/sdf_process_constructors.hpp b/src/forsyde/sdf_process_constructors.hpp index 6ce1f97..deef9a6 100644 --- a/src/forsyde/sdf_process_constructors.hpp +++ b/src/forsyde/sdf_process_constructors.hpp @@ -25,6 +25,8 @@ #include #include #include +#include + #include "sdf_process.hpp" @@ -1205,8 +1207,8 @@ class zipN : public sdf_process * zips them together and writes the results using the output port */ zipN(sc_module_name _name, - std::vector in_toks) - :sdf_process(_name), oport1("oport1"), in_toks(in_toks) + std::initializer_list in_toks) + :sdf_process(_name), oport1("oport1"), in_toks(std::vector(in_toks)) { if (in_toks.size()!=sizeof...(Ts)) SC_REPORT_ERROR(name(),"Wrong number of production rates provided"); @@ -1231,7 +1233,7 @@ class zipN : public sdf_process void prep() { - *in_val = sc_fifo_tuple_read(iport, in_toks); + in_val->t = sc_fifo_tuple_read(iport, in_toks); } void exec() {} @@ -1405,8 +1407,8 @@ class unzipN : public sdf_process * unzips it and writes the results using the output ports */ unzipN(sc_module_name _name, - std::vector out_toks) - :sdf_process(_name), iport1("iport1"), out_toks(out_toks) + std::initializer_list out_toks) + :sdf_process(_name), iport1("iport1"), out_toks(std::vector(out_toks)) { if (out_toks.size()!=sizeof...(Ts)) SC_REPORT_ERROR(name(),"Wrong number of production rates provided"); diff --git a/src/forsyde/sdf_types.hpp b/src/forsyde/sdf_types.hpp index 0948f73..6ab678f 100644 --- a/src/forsyde/sdf_types.hpp +++ b/src/forsyde/sdf_types.hpp @@ -51,9 +51,6 @@ struct token_tuple { traverse_tuple::resize(list.end(), t); } - template< std::size_t I, std::size_t N > - auto get() { return std::get(t)[N]; } - template< std::size_t I> auto get(size_t n) { return std::get(t)[n]; } @@ -76,9 +73,10 @@ struct token_tuple { // Template specialization for traversing a tuple with multiple elements template struct traverse_tuple, Tail...>>{ - static inline void resize(std::initializer_list::iterator size, std::tuple, Tail...> tv) { + static inline void resize(std::initializer_list::iterator size, std::tuple, Tail...>& tv) { --size; std::get(tv).resize(*size); + //std::cout << std::endl << N-1 << " : " << std::get(tv).size() << std::endl; traverse_tuple, Tail...>>::resize(size, tv); } }; @@ -86,8 +84,9 @@ struct token_tuple { // Template specialization for traversing a tuple with one element template struct traverse_tuple<1, std::tuple, Tail...>>{ - static inline void resize(std::initializer_list::iterator size, std::tuple, Tail...> tv) { + static inline void resize(std::initializer_list::iterator size, std::tuple, Tail...>& tv) { std::get<0>(tv).resize(*size); + //std::cout << std::endl << 0 << " : " << std::get<0>(tv).size() << std::endl; } }; @@ -107,10 +106,6 @@ template void resize(size_t n, tokens v){ return v.resize(n); } -template -T& get(tokens v){ - return v.at(N); -} template tokens> init(size_t n, std::initializer_list list){ @@ -120,15 +115,76 @@ template void resize(size_t n, std::initializer_list list, tokens> v ){ return v.resize(n); } -template< std::size_t N1, std::size_t N2, std::size_t N3, typename... T > -auto get(tokens> v) { - return v[N1].get(); -} + +template +T& get(tokens& v){ return v.at(N); } + +template +T get(const tokens v){ return v.at(N); } + template< std::size_t N1, std::size_t N2, typename... T > -auto get_tokens(tokens> v) { - return std::get(v[N1].t); -} +typename std::tuple_element >::type& +get(token_tuple& v) { return std::get(v.t).at(N2); } + +template< std::size_t N1, std::size_t N2, typename... T > +typename std::tuple_element >::type +get(const token_tuple& v) { return std::get(v.t).at(N2); } + +template< std::size_t N1, std::size_t N2, typename... T > +typename std::tuple_element >::type* +get(tokens>& v) { return &std::get(v.at(N1).t)[0]; } + +template< std::size_t N1, std::size_t N2, typename... T > +typename std::tuple_element >::type const* +get(const tokens>& v) { return &std::get(v.at(N1).t)[0]; } + +template< std::size_t N1, std::size_t N2, std::size_t N3, typename... T > +typename std::tuple_element >::type& +get(tokens>& v) { return std::get(v.at(N1).t).at(N3); } + +template< std::size_t N1, std::size_t N2, std::size_t N3, typename... T > +typename std::tuple_element >::type +get(const tokens>& v) { return std::get(v.at(N1).t).at(N3); } + + + +/////////////////////////////// + +/* +template +struct get_{ + T& operator()(T& t) { return t; } + T const& operator()(const T& t) { return t; } +}; + +template +struct get_<1, T, Ixs...> { + T& operator()(T& t) { return t; } + T const& operator()(const T& t) { return t; } +}; + + +template +struct get_, Ix, Ixs...> { + T& operator()(tokens& t) { return get_(t.at(Ix)); } + T const& operator()(const tokens& t) { return get_(t.at(Ix)); } +}; + +template +struct get_, Ix, Ixs...> { + auto& operator()(token_tuple& t) { + auto x = std::get(t.t); + return get_ (x); + } + auto const& operator()(const token_tuple& t) { + auto x = std::get(t.t); + return get_ (x); + } +}; +*/ +// check http://stackoverflow.com/questions/28147849/c-template-meta-programming-member-function-loop-unrolling +// for loops on template functions } } diff --git a/src/forsyde/types.hpp b/src/forsyde/types.hpp index 3a80655..1b58bf7 100644 --- a/src/forsyde/types.hpp +++ b/src/forsyde/types.hpp @@ -217,6 +217,10 @@ class TypeContainer { xml_doc.append_node(root_node); }; + ~TypeContainer() { + xml_doc.clear(); + }; + // these are needed to ensure singleton pattern TypeContainer(TypeContainer const&); void operator=(TypeContainer const&); diff --git a/src/forsyde/xml.hpp b/src/forsyde/xml.hpp index 8f416bd..815893a 100644 --- a/src/forsyde/xml.hpp +++ b/src/forsyde/xml.hpp @@ -101,7 +101,6 @@ class XMLExport { // Initiate the XML file for this level of hierarchy xml_node<>* pn_node = init(top); - std::cout<<"parsing " << pn_node->name(); // Get the list of module children (ports and other processes) std::vector children = top->get_child_objects(); From 32a9126044592294c7f5b205144e4fb3aa9e0462 Mon Sep 17 00:00:00 2001 From: ugeorge Date: Mon, 21 Mar 2016 01:36:38 +0100 Subject: [PATCH 09/18] fixed bug with get template and zup/unzip helper --- src/forsyde/sdf_helpers.hpp | 4 ++-- src/forsyde/sdf_types.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/forsyde/sdf_helpers.hpp b/src/forsyde/sdf_helpers.hpp index bc90791..f2aa01e 100644 --- a/src/forsyde/sdf_helpers.hpp +++ b/src/forsyde/sdf_helpers.hpp @@ -345,7 +345,7 @@ template class I1If, inline zip* make_zip(std::string pName, unsigned int i1toks, unsigned int i2toks, - OIf,std::vector>>& outS, + OIf>& outS, I1If& inp1S, I2If& inp2S ) @@ -370,7 +370,7 @@ template