.. _program_listing_file_falcon_connectionparser.cpp: Program Listing for File connectionparser.cpp ============================================= |exhale_lsh| :ref:`Return to documentation for file ` (``falcon/connectionparser.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // --------------------------------------------------------------------- // This file is part of falcon-core. // // Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders // // Falcon-server is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Falcon-server is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with falcon-core. If not, see . // --------------------------------------------------------------------- #include #include #include #include #include #include "connectionparser.hpp" #include "utilities/string.hpp" ConnectionRule parseConnectionRule(std::string rulestring) { // rule // :.:.: // specifier is one of f (processor), p (port) or s (slot) // name is any character in [a-zA-Z_] // id is either: number or list of ranges (e.g. [1, 4-8, 10]) static const int type_specifier = 1; static const int name_group = 2; static const int range_group = 3; static const int first_range_id = 1; static const int end_range_id = 2; ConnectionRule rule; SingleConnectionRule single_rules[2]; std::string expr("^(?:(f|p|s)\\:)?([a-zA-Z]*(?:[ -_][a-zA-Z]+)*)[ " "]*((?:\\d+)|(?:\\([\\d,\\-]+\\)))?$"); std::regex re(expr); std::smatch match; int startid; int endid; int current_rule_part = 0; int current_connection_part; // split on "=" auto rule_parts = split(rulestring, '='); if (rule_parts.size() != 2 || rule_parts[0].length() == 0 || rule_parts[1].length() == 0) { throw std::runtime_error( "Error parsing connection rule. Use the following pattern: " "[upstream] = [downstream]."); } for (auto &rule_part : rule_parts) { rule_part = std::regex_replace(rule_part, std::regex("^ +| +$"), std::string("")); // split on "." auto connection_parts = split(rule_part, '.'); if (connection_parts.size() > 3) { throw std::runtime_error("Error parsing connection rule. " "Port/slot address can have at most 3 parts " "(given: " + rule_part + ")."); } current_connection_part = 0; std::list available_specifiers{PROCESSOR, PORT, SLOT}; NodePart specifier; for (auto &connection_part : connection_parts) { // match regular expression if (!std::regex_match(connection_part, match, re)) { throw std::runtime_error("Error parsing connection rule. " "Cannot parse part of address: " + connection_part + "."); } // parse part specifier if (!match[type_specifier].matched) { // get next available specifier specifier = available_specifiers.front(); available_specifiers.pop_front(); } else { // check if specifier is available std::string type_spec = match[type_specifier].str(); if (type_spec == "f") { specifier = PROCESSOR; } else if (type_spec == "p") { specifier = PORT; } else { specifier = SLOT; } auto it = std::find(available_specifiers.begin(), available_specifiers.end(), specifier); if (it == available_specifiers.end()) { throw std::runtime_error( "Error parsing connection rule. Duplicate address specifier."); } available_specifiers.remove(specifier); } // parse part name if (!match[name_group].matched && specifier != SLOT) { throw std::runtime_error("Error parsing connection rule. " "Invalid processor or port name: " + connection_part + "."); } std::string name = match[name_group].str(); // parse part identifiers std::vector identifiers; if (!match[range_group].matched) { // match all or default if (specifier == SLOT) { identifiers.push_back(-1); } else { identifiers.push_back(MATCH_NONE); } } else { std::string range = match[range_group].str(); if (range[0] == '(') { // match ID range vector // remove brackets and spaces range.erase(std::remove_if(range.begin(), range.end(), [](char x) { return (x == '(' || x == ')' || std::isspace(x)); }), range.end()); // split on comma auto id_range = split(range, ','); std::regex re_range("(\\d+)(?:\\-(\\d+))?"); std::smatch match_range; // match start and end id of ranges for (const auto &q : id_range) { if (std::regex_match(q, match_range, re_range)) { startid = stoi(match_range[first_range_id].str()); if (match_range[end_range_id].matched) { endid = stoi(match_range[end_range_id].str()); } else { endid = startid; } for (auto kk = startid; kk <= endid; kk++) { identifiers.push_back(kk); } } else { throw std::runtime_error("Error parsing connection rule. " "Cannot parse range: " + q + "."); } } } else { // try to convert to int try { identifiers.push_back(stoi(range)); } catch (std::invalid_argument &e) { throw std::runtime_error("Error parsing connection rule. " "Cannot parse range: " + range + "."); } } } if(specifier == PORT){ name = std::regex_replace(name, std::regex("[ _]"), "-"); } // construct ConnectionPart and add to SingleConnectionRule single_rules[current_rule_part][current_connection_part] = std::make_tuple(specifier, name, identifiers); current_connection_part++; } // TODO: complete missing ConnectionParts of SingleConnectionRule // go through available specifiers for (auto &k : available_specifiers) { if (k == PROCESSOR) { throw std::runtime_error("Error parsing connection rule. " "No processor specified"); } else if (k == PORT) { single_rules[current_rule_part][current_connection_part] = std::make_tuple(PORT, std::string(""), std::vector(1, MATCH_NONE)); } else if (k == SLOT) { single_rules[current_rule_part][current_connection_part] = std::make_tuple(SLOT, std::string(""), std::vector(1, -1)); } current_connection_part++; } current_rule_part++; } // construct ConnectionRule from both SingleConnectionRules rule = std::make_pair(single_rules[0], single_rules[1]); return rule; } std::vector expandSingleConnectionRule(SingleConnectionRule rule) { std::array index; std::array names; int idx; std::array tmp; std::string processor; std::string port; int slot = -1; std::vector cpoints; for (int i = 0; i < 3; i++) { idx = std::get<0>(rule[i]); index[i] = idx; names[i] = std::get<1>(rule[i]); } for (auto a : std::get<2>(rule[0])) { for (auto b : std::get<2>(rule[1])) { for (auto c : std::get<2>(rule[2])) { tmp[0] = a; tmp[1] = b; tmp[2] = c; for (int d = 0; d < 3; d++) { if (index[d] == 0) { // processor if (tmp[d] == MATCH_NONE) { processor = names[d]; } else { processor = names[d] + std::to_string(tmp[d]); } } else if (index[d] == 1) { // port if (tmp[d] == MATCH_NONE) { port = names[d]; } else { port = names[d] + std::to_string(tmp[d]); } } else { // slot slot = tmp[d]; } } cpoints.push_back(SlotAddress(processor, port, slot)); } } } return cpoints; } void expandConnectionRule(ConnectionRule rule, StreamConnections &connections) { // for output SingleConnectionRule auto out = rule.first; auto out_points = expandSingleConnectionRule(out); // for input SingleConnectionRule auto in = rule.second; auto in_points = expandSingleConnectionRule(in); if (out_points.size() != 1 && out_points.size() != in_points.size()) { throw std::runtime_error("Invalid connection rule: number of outputs and " "inputs does not match."); } if (out_points.size() == 1) { for (int i = 0; i < (int)in_points.size(); i++) { connections.push_back(std::make_pair(out_points[0], in_points[i])); } } else { for (int i = 0; i < (int)out_points.size(); i++) { connections.push_back(std::make_pair(out_points[i], in_points[i])); } } } void printConnectionPart(const ConnectionPart &part) { std::cout << std::get<0>(part); std::cout << std::get<1>(part); auto v = std::get<2>(part); if (v.size() > 0 && v[0] >= 0) { std::cout << "["; for (auto &it : v) { std::cout << it << ", "; } std::cout << "]"; } } void printSingleConnectionRule(const SingleConnectionRule &rule) { for (int i = 0; i < 3; i++) { printConnectionPart(rule[i]); if (i < 2) { std::cout << "."; } } } void printConnectionRule(const ConnectionRule &rule) { printSingleConnectionRule(rule.first); std::cout << " = "; printSingleConnectionRule(rule.second); std::cout << std::endl; } void printConnectionList(const StreamConnections &connections) { for (auto &it : connections) { std::cout << it.first.string() << "=" << it.second.string() << std::endl; } }