1+ /*
2+ * This program is free software: you can redistribute it and/or modify
3+ * it under the terms of the GNU General Public License as published by
4+ * the Free Software Foundation, either version 3 of the License, or
5+ * (at your option) any later version.
6+ *
7+ * This program is distributed in the hope that it will be useful,
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+ * GNU General Public License for more details.
11+ *
12+ * You should have received a copy of the GNU General Public License
13+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
14+ */
15+
16+ /*
17+ * Copyright Dan Kristiansen and Morten K. Schou
18+ */
19+
20+ /*
21+ * File: TopologyBuilder.cpp
22+ * Author: Dan Kristiansen
23+ *
24+ * Created on 04-06-2020.
25+ */
26+
27+ #include < fstream>
28+ #include < sstream>
29+ #include " TopologyBuilder.h"
30+
31+ namespace aalwines {
32+
33+ // Stolen from: https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
34+ // trim from start (in place)
35+ static inline void ltrim (std::string &s) {
36+ s.erase (s.begin (), std::find_if (s.begin (), s.end (), [](int ch) {
37+ return !std::isspace (ch);
38+ }));
39+ }
40+ // trim from end (in place)
41+ static inline void rtrim (std::string &s) {
42+ s.erase (std::find_if (s.rbegin (), s.rend (), [](int ch) {
43+ return !std::isspace (ch);
44+ }).base (), s.end ());
45+ }
46+ // trim from both ends (in place)
47+ static inline void trim (std::string &s) {
48+ ltrim (s);
49+ rtrim (s);
50+ }
51+
52+ Network aalwines::TopologyBuilder::parse (const std::string &gml, std::ostream& warnings) {
53+ std::ifstream file (gml);
54+
55+ if (not file){
56+ std::cerr << " Error file not found." << std::endl;
57+ }
58+
59+ std::vector<std::pair<size_t , size_t >> _all_links;
60+ std::vector<std::pair<std::string, Coordinate>> _all_routers;
61+ std::map<const size_t , std::string> _router_map;
62+ std::vector<std::vector<std::string>> _return_links;
63+
64+ std::string str;
65+ while (std::getline (file, str, ' ' )) {
66+ if (str ==" node" ) {
67+ size_t id;
68+ std::string router_name;
69+ double latitude = 0 ;
70+ double longitude = 0 ;
71+ while (std::getline (file, str)){
72+ trim (str);
73+ auto pos = str.find (' ' );
74+ if (pos == str.size ()) continue ;
75+ std::string key = str.substr (0 , pos);
76+ if (key == " id" ){
77+ id = std::stoul (str.substr (pos+1 ));
78+ }
79+ else if (key == " label" ){
80+ router_name = str.substr (pos+2 , str.size () - pos - 3 );
81+ trim (router_name);
82+ // Get_interface dont handle ' ' very well
83+ std::replace (router_name.begin (), router_name.end (), ' ' , ' _' );
84+ router_name.erase (std::remove_if (router_name.begin (), router_name.end (),
85+ [](auto const & c) -> bool { return !std::isalnum (c) && c != ' _' && c != ' -' ; }), router_name.end ());
86+ }
87+ else if (key == " Latitude" ){
88+ latitude = std::stod (str.substr (pos+1 ));
89+ }
90+ else if (key == " Longitude" ){
91+ longitude = std::stod (str.substr (pos+1 ));
92+ }
93+ else if (key == " ]" ){
94+ bool indexer_active = false ;
95+ while (std::find_if ( _all_routers.begin (), _all_routers.end (),
96+ [&]( std::pair<std::string,Coordinate> &item ) { return item.first == router_name; } )
97+ != _all_routers.end ()) {
98+ if (indexer_active){
99+ if ((int ) router_name[router_name.size ()-1 ]++ - 48 > 5 ) assert (false );
100+ } else {
101+ router_name += " 2" ;
102+ indexer_active = true ;
103+ }
104+ }
105+ assert (latitude != 0 or longitude != 0 );
106+ _all_routers.emplace_back (router_name, Coordinate{latitude, longitude});
107+ _router_map.insert ({id, router_name});
108+ _return_links.emplace_back ();
109+ break ;
110+ }
111+ }
112+ }
113+ else if (str == " edge" ){
114+ size_t source;
115+ size_t target;
116+ while (std::getline (file, str, ' ' )) {
117+ if (str == " source" ) {
118+ file >> source;
119+ } else if (str == " target" ) {
120+ file >> target;
121+ _all_links.emplace_back (source, target);
122+ break ;
123+ }
124+ }
125+ }
126+ }
127+
128+ for (size_t i = 0 ; i < _all_routers.size (); i++){
129+ for (auto & link : _all_links){
130+ if (link.first == i){
131+ _return_links[i].emplace_back (_router_map[link.second ]);
132+ _return_links[link.second ].emplace_back (_router_map[link.first ]);
133+ }
134+ }
135+ }
136+ return Network::make_network (_all_routers, _return_links);
137+ }
138+
139+ inline json to_json_no_routing (const Router& router) {
140+ auto j = json::object ();
141+ j[" names" ] = router.names ();
142+ j[" interfaces" ] = json::array ();
143+ for (const auto & interface : router.interfaces ()) {
144+ auto j_i = json::object ();
145+ j_i[" name" ] = interface->get_name ();
146+ j_i[" routing_table" ] = json::object (); // Only topology, so empty routing_table in this mode.
147+ j[" interfaces" ].push_back (j_i);
148+ }
149+ if (router.coordinate ()) {
150+ j[" location" ] = router.coordinate ().value ();
151+ }
152+ return j;
153+ }
154+
155+ json TopologyBuilder::json_topology (const Network& network, bool no_routing) {
156+ auto j = json::object ();
157+ j[" name" ] = network.name ;
158+ j[" routers" ] = json::array ();
159+ for (const auto & router : network.routers ()) {
160+ if (router->is_null ()) continue ;
161+ if (no_routing) {
162+ j[" routers" ].push_back (to_json_no_routing (*router));
163+ } else {
164+ j[" routers" ].push_back (router);
165+ }
166+ }
167+ auto links_j = json::array ();
168+ for (const auto & interface : network.all_interfaces ()){
169+ if (interface->match () == nullptr ) continue ; // Not connected
170+ if (interface->source ()->is_null () || interface->target ()->is_null ()) continue ; // Skip the NULL router
171+ assert (interface->match ()->match () == interface);
172+ if (interface->global_id () > interface->match ()->global_id ()) continue ; // Already covered by bidirectional link the other way.
173+
174+ auto link_j = json::object ();
175+ link_j[" from_interface" ] = interface->get_name ();
176+ link_j[" from_router" ] = interface->source ()->name ();
177+ link_j[" to_interface" ] = interface->match ()->get_name ();
178+ link_j[" to_router" ] = interface->target ()->name ();
179+ link_j[" bidirectional" ] = true ;
180+ links_j.push_back (link_j);
181+ }
182+ j[" links" ] = links_j;
183+ return j;
184+ }
185+ }
0 commit comments