diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp index e3f09290..e3a0d7da 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp @@ -97,29 +97,6 @@ void HGEdge::detach() detach(vertex2->incident_edges); } -// write line to tmg collapsed edge file -void HGEdge::collapsed_tmg_line(std::ofstream& file, char* fstr, unsigned int threadnum, std::vector *systems) -{ file << vertex1->c_vertex_num[threadnum] << ' ' << vertex2->c_vertex_num[threadnum] << ' '; - segment->write_label(file, systems); - for (HGVertex *intermediate : intermediate_points) - { *fmt::format_to(fstr, " {:.15} {:.15}", intermediate->lat, intermediate->lng) = 0; - file << fstr; - } - file << '\n'; -} - -// write line to tmg traveled edge file -void HGEdge::traveled_tmg_line(std::ofstream& file, char* fstr, unsigned int threadnum, std::vector *systems, bool trav, char* code) -{ file << vertex1->t_vertex_num[threadnum] << ' ' << vertex2->t_vertex_num[threadnum] << ' '; - segment->write_label(file, systems); - file << ' ' << (trav ? segment->clinchedby_code(code, threadnum) : "0"); - for (HGVertex *intermediate : intermediate_points) - { *fmt::format_to(fstr, " {:.15} {:.15}", intermediate->lat, intermediate->lng) = 0; - file << fstr; - } - file << '\n'; -} - /* line appropriate for a tmg collapsed edge file, with debug info std::string HGEdge::debug_tmg_line(std::vector *systems, unsigned int threadnum) { std::string line = std::to_string(vertex1->c_vertex_num[threadnum]) + " [" + *vertex1->unique_name + "] " \ diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h index eae10da8..c1667b27 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h @@ -31,8 +31,6 @@ class HGEdge HGEdge(HGVertex *, unsigned char, HGEdge*, HGEdge*); void detach(); - void collapsed_tmg_line(std::ofstream&, char*, unsigned int, std::vector*); - void traveled_tmg_line (std::ofstream&, char*, unsigned int, std::vector*, bool, char*); std::string debug_tmg_line(std::vector *, unsigned int); std::string str(); std::string intermediate_point_string(); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp index 80190149..88ca5e87 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp @@ -1,3 +1,4 @@ +#define FMT_HEADER_ONLY #include "HGVertex.h" #include "../Args/Args.h" #include "../Datacheck/Datacheck.h" @@ -6,17 +7,15 @@ #include "../Region/Region.h" #include "../Route/Route.h" #include "../Waypoint/Waypoint.h" +#include std::atomic_uint HGVertex::num_hidden(0); +thread_local int* HGVertex::vnums; void HGVertex::setup(Waypoint *wpt, const std::string *n) { lat = wpt->lat; lng = wpt->lng; wpt->vertex = this; - s_vertex_num = new int[Args::numthreads]; - c_vertex_num = new int[Args::numthreads]; - t_vertex_num = new int[Args::numthreads]; - // deleted by ~HGVertex unique_name = n; edge_count = 0; visibility = 0; @@ -38,13 +37,6 @@ void HGVertex::setup(Waypoint *wpt, const std::string *n) else num_hidden++; } -HGVertex::~HGVertex() -{ //std::cout << "deleting vertex at " << first_waypoint->str() << std::endl; - delete[] s_vertex_num; - delete[] c_vertex_num; - delete[] t_vertex_num; -} - HGEdge* HGVertex::front(unsigned char format) { for (HGEdge* e : incident_edges) if (e->format & format) @@ -66,3 +58,12 @@ HGEdge* HGVertex::back(unsigned char format) // Nonetheless, let's stop the compiler from complaining. throw this; } + +void HGVertex::format_coordstr() +{ // sanity checks to avoid buffer overflows via >3 digits to L of decimal point + while (lat > 90) lat -= 360; + while (lat < -90) lat += 360; + while (lng >= 540) lng -= 360; + while (lng <= -540) lng += 360; + *fmt::format_to(coordstr, " {:.15} {:.15}", lat, lng) = 0; +} diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.h b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.h index 61d61d5d..1cd1ffbf 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.h @@ -14,17 +14,16 @@ class HGVertex double lat, lng; const std::string *unique_name; std::vector incident_edges; - int *s_vertex_num; - int *c_vertex_num; - int *t_vertex_num; uint16_t edge_count; char visibility; + char coordstr[45]; // only need 43, but alignment requires extra anyway static std::atomic_uint num_hidden; + static thread_local int* vnums; void setup(Waypoint*, const std::string*); - ~HGVertex(); HGEdge* front(unsigned char); HGEdge* back (unsigned char); + void format_coordstr(); }; diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index 3d9d6b74..651a0679 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -14,8 +14,7 @@ #include "../Waypoint/Waypoint.h" #include "../WaypointQuadtree/WaypointQuadtree.h" #include "../../templates/contains.cpp" -#include -#include +#include #include HighwayGraph::HighwayGraph(WaypointQuadtree &all_waypoints, ElapsedTime &et) @@ -374,13 +373,13 @@ void HighwayGraph::write_master_graphs_tmg() unsigned int sv = 0; unsigned int cv = 0; unsigned int tv = 0; - char fstr[57]; + int* vnum = HGVertex::vnums; for (HGVertex& v : vertices) - { *fmt::format_to(fstr, " {:.15} {:.15}", v.lat, v.lng) = 0; - switch (v.visibility) // fall-thru is a Good Thing! - { case 2: collapfile << *(v.unique_name) << fstr << '\n'; v.c_vertex_num[0] = cv++; - case 1: travelfile << *(v.unique_name) << fstr << '\n'; v.t_vertex_num[0] = tv++; - default: simplefile << *(v.unique_name) << fstr << '\n'; v.s_vertex_num[0] = sv++; + { switch (v.visibility) // fall-thru is a Good Thing! + { case 2: collapfile << *(v.unique_name) << v.coordstr << '\n'; vnum[1] = cv++; + case 1: travelfile << *(v.unique_name) << v.coordstr << '\n'; vnum[2] = tv++; + default: simplefile << *(v.unique_name) << v.coordstr << '\n'; vnum[0] = sv++; + vnum += 3; } } @@ -393,16 +392,28 @@ void HighwayGraph::write_master_graphs_tmg() // write edges //TODO: multiple functions performing the same instructions for multiple files? for (HGEdge *e = edges.begin(), *end = edges.end(); e != end; ++e) - { if (e->format & HGEdge::collapsed) - e->collapsed_tmg_line(collapfile, fstr, 0, 0); + { int* v1num = HGVertex::vnums+(e->vertex1-vertices.data())*3; + int* v2num = HGVertex::vnums+(e->vertex2-vertices.data())*3; + + if (e->format & HGEdge::collapsed) + { fmt::print(collapfile, "{} {} ", v1num[1], v2num[1]); + collapfile << e->segment_name; + for (HGVertex *intermediate : e->intermediate_points) + collapfile << intermediate->coordstr; + collapfile << '\n'; + } if (e->format & HGEdge::traveled) { for (char*n=cbycode; ntraveled_tmg_line(travelfile, fstr, 0, 0, TravelerList::allusers.size, cbycode); + fmt::print(travelfile, "{} {} ", v1num[2], v2num[2]); + travelfile << e->segment_name; + travelfile << ' ' << (TravelerList::allusers.size ? e->segment->clinchedby_code(cbycode, 0) : "0"); + for (HGVertex *intermediate : e->intermediate_points) + travelfile << intermediate->coordstr; + travelfile << '\n'; } if (e->format & HGEdge::simple) - { simplefile << e->vertex1->s_vertex_num[0] << ' ' - << e->vertex2->s_vertex_num[0] << ' '; - e->segment->write_label(simplefile, 0); + { fmt::print(simplefile, "{} {} ", v1num[0], v2num[0]); + simplefile << e->segment_name; simplefile << '\n'; } } @@ -466,16 +477,11 @@ void HighwayGraph::write_subgraphs_tmg travelfile << tv_count << ' ' << te_count << ' ' << travnum << '\n'; // write vertices - unsigned int sv = 0; - unsigned int cv = 0; - unsigned int tv = 0; - char fstr[57]; for (HGVertex *v : mv) - { *fmt::format_to(fstr, " {:.15} {:.15}", v->lat, v->lng) = 0; - switch(v->visibility) // fall-thru is a Good Thing! - { case 2: collapfile << *(v->unique_name) << fstr << '\n'; v->c_vertex_num[threadnum] = cv++; - case 1: travelfile << *(v->unique_name) << fstr << '\n'; v->t_vertex_num[threadnum] = tv++; - default: simplefile << *(v->unique_name) << fstr << '\n'; v->s_vertex_num[threadnum] = sv++; + { switch(v->visibility) // fall-thru is a Good Thing! + { case 2: collapfile << *(v->unique_name) << v->coordstr << '\n'; + case 1: travelfile << *(v->unique_name) << v->coordstr << '\n'; + default: simplefile << *(v->unique_name) << v->coordstr << '\n'; } } @@ -487,17 +493,35 @@ void HighwayGraph::write_subgraphs_tmg // write edges for (HGEdge *e : me) //TODO: multiple functions performing the same instructions for multiple files? - { if (e->format & HGEdge::simple) - { simplefile << e->vertex1->s_vertex_num[threadnum] << ' ' - << e->vertex2->s_vertex_num[threadnum] << ' '; - e->segment->write_label(simplefile, g->systems); + { int* v1num = HGVertex::vnums+(e->vertex1-vertices.data())*3; + int* v2num = HGVertex::vnums+(e->vertex2-vertices.data())*3; + + if (e->format & HGEdge::simple) + { fmt::print(simplefile, "{} {} ", v1num[0], v2num[0]); + if (g->systems) + e->segment->write_label(simplefile, g->systems); + else simplefile << e->segment_name; simplefile << '\n'; } if (e->format & HGEdge::collapsed) - e->collapsed_tmg_line(collapfile, fstr, threadnum, g->systems); + { fmt::print(collapfile, "{} {} ", v1num[1], v2num[1]); + if (g->systems) + e->segment->write_label(collapfile, g->systems); + else collapfile << e->segment_name; + for (HGVertex *intermediate : e->intermediate_points) + collapfile << intermediate->coordstr; + collapfile << '\n'; + } if (e->format & HGEdge::traveled) { for (char*n=cbycode; ntraveled_tmg_line (travelfile, fstr, threadnum, g->systems, travnum, cbycode); + fmt::print(travelfile, "{} {} ", v1num[2], v2num[2]); + if (g->systems) + e->segment->write_label(travelfile, g->systems); + else travelfile << e->segment_name; + travelfile << ' ' << (travnum ? e->segment->clinchedby_code(cbycode, threadnum) : "0"); + for (HGVertex *intermediate : e->intermediate_points) + travelfile << intermediate->coordstr; + travelfile << '\n'; } } delete[] cbycode; diff --git a/siteupdate/cplusplus/classes/GraphGeneration/get_subgraph_data.cpp b/siteupdate/cplusplus/classes/GraphGeneration/get_subgraph_data.cpp index 6e153f2e..285d9fab 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/get_subgraph_data.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/get_subgraph_data.cpp @@ -49,12 +49,13 @@ else { // We know there's a PlaceRadius, as no GraphListEntry me.shrink_to_fit(); } -// count vertices +// count vertices & initialize vertex numbers for (HGVertex* v : mv) -{ switch (v->visibility) // fall-thru is a Good Thing! - { case 2: cv_count++; - case 1: tv_count++; - default: sv_count++; +{ int* vnum = HGVertex::vnums+(v-vertices.data())*3; + switch (v->visibility) // fall-thru is a Good Thing! + { case 2: vnum[1] = cv_count++; + case 1: vnum[2] = tv_count++; + default: vnum[0] = sv_count++; } } diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp index 8e9e9f90..deb4f39b 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp @@ -97,12 +97,13 @@ const char* HighwaySegment::clinchedby_code(char* code, unsigned int threadnum) return code; } -// compute an edge label, optionally restricted by systems +// write an edge label, restricted by systems void HighwaySegment::write_label(std::ofstream& file, std::vector *systems) { if (concurrent) { bool write_comma = 0; for (HighwaySegment* cs : *concurrent) - if ( !cs->route->system->devel() && (!systems || contains(*systems, cs->route->system)) ) + // This function is only called when systems is nonzero. Safe to dereference. + if ( !cs->route->system->devel() && contains(*systems, cs->route->system) ) { if (write_comma) file << ','; else write_comma = 1; file << cs->route->route; diff --git a/siteupdate/cplusplus/tasks/graph_generation.cpp b/siteupdate/cplusplus/tasks/graph_generation.cpp index fcee32fd..4e75ba39 100644 --- a/siteupdate/cplusplus/tasks/graph_generation.cpp +++ b/siteupdate/cplusplus/tasks/graph_generation.cpp @@ -12,6 +12,14 @@ graph_data.waypoint_naming_log.clear(); { // Let's keep these braces here, for easily commenting out subgraph generation when developing waypoint simplification routines GraphListEntry::num = 3; + cout << et.et() << "Formatting vertex coordinate strings." << endl; + #ifdef threading_enabled + THREADLOOP thr[t] = thread(VtxFmtThread, t, &graph_data.vertices); + THREADLOOP thr[t].join(); + #else + for (HGVertex& v : graph_data.vertices) v.format_coordstr(); + #endif + cout << et.et() << "Writing master TM graph files." << endl; // print summary info std::cout << " Simple graph has " << graph_data.vertices.size() << " vertices, " << graph_data.se << " edges." << std::endl; @@ -26,10 +34,12 @@ graph_data.waypoint_naming_log.clear(); thr[t] = thread(SubgraphThread, t, &list_mtx, &term_mtx, &graph_data, &all_waypoints, &et); THREADLOOP thr[t].join(); #else + HGVertex::vnums = new int[graph_data.vertices.size()*3]; for ( graph_data.write_master_graphs_tmg(); GraphListEntry::num < GraphListEntry::entries.size(); GraphListEntry::num += 3 ) graph_data.write_subgraphs_tmg(GraphListEntry::num, 0, &all_waypoints, &et, &term_mtx); + delete[] HGVertex::vnums; #endif cout << '!' << endl; } //*/ diff --git a/siteupdate/cplusplus/threads/MasterTmgThread.cpp b/siteupdate/cplusplus/threads/MasterTmgThread.cpp index 23b1f898..ececcc86 100644 --- a/siteupdate/cplusplus/threads/MasterTmgThread.cpp +++ b/siteupdate/cplusplus/threads/MasterTmgThread.cpp @@ -1,4 +1,6 @@ void MasterTmgThread(HighwayGraph* graph_data, std::mutex* l, std::mutex* t, WaypointQuadtree *qt, ElapsedTime *et) -{ graph_data->write_master_graphs_tmg(); +{ HGVertex::vnums = new int[graph_data->vertices.size()*3]; + graph_data->write_master_graphs_tmg(); + delete[] HGVertex::vnums; SubgraphThread(0, l, t, graph_data, qt, et); } diff --git a/siteupdate/cplusplus/threads/SubgraphThread.cpp b/siteupdate/cplusplus/threads/SubgraphThread.cpp index 84bf5e4f..26f7690e 100644 --- a/siteupdate/cplusplus/threads/SubgraphThread.cpp +++ b/siteupdate/cplusplus/threads/SubgraphThread.cpp @@ -3,6 +3,7 @@ void SubgraphThread HighwayGraph* graph_data, WaypointQuadtree* qt, ElapsedTime* et ) { //std::cout << "Starting SubgraphThread " << id << std::endl; + HGVertex::vnums = new int[graph_data->vertices.size()*3]; while (GraphListEntry::num < GraphListEntry::entries.size()) { l->lock(); if (GraphListEntry::num >= GraphListEntry::entries.size()) @@ -16,4 +17,5 @@ void SubgraphThread l->unlock(); graph_data->write_subgraphs_tmg(i, id, qt, et, t); } + delete[] HGVertex::vnums; } diff --git a/siteupdate/cplusplus/threads/VtxFmtThread.cpp b/siteupdate/cplusplus/threads/VtxFmtThread.cpp new file mode 100644 index 00000000..ec4ada06 --- /dev/null +++ b/siteupdate/cplusplus/threads/VtxFmtThread.cpp @@ -0,0 +1,4 @@ +void VtxFmtThread(unsigned int id, std::vector* vertices) +{ for (auto v = vertices->begin()+id, end = vertices->end(); v < end; v += Args::numthreads) + v->format_coordstr(); +} diff --git a/siteupdate/cplusplus/threads/threads.cpp b/siteupdate/cplusplus/threads/threads.cpp index 302c9822..ea0a3a36 100644 --- a/siteupdate/cplusplus/threads/threads.cpp +++ b/siteupdate/cplusplus/threads/threads.cpp @@ -1,5 +1,6 @@ #include "threads.h" #include "../classes/GraphGeneration/GraphListEntry.h" +#include "../classes/GraphGeneration/HGVertex.h" #include "../classes/GraphGeneration/HighwayGraph.h" #include "../classes/HighwaySegment/HighwaySegment.h" #include "../classes/HighwaySystem/HighwaySystem.h" @@ -22,3 +23,4 @@ #include "StatsCsvThread.cpp" #include "SubgraphThread.cpp" #include "UserLogThread.cpp" +#include "VtxFmtThread.cpp" diff --git a/siteupdate/cplusplus/threads/threads.h b/siteupdate/cplusplus/threads/threads.h index 367aac85..aa24ee9f 100644 --- a/siteupdate/cplusplus/threads/threads.h +++ b/siteupdate/cplusplus/threads/threads.h @@ -1,5 +1,6 @@ class ElapsedTime; class ErrorList; +class HGVertex; class HighwayGraph; class WaypointQuadtree; #include @@ -16,3 +17,4 @@ void RteIntThread (unsigned int, std::mutex*, ErrorList*); void StatsCsvThread (unsigned int, std::mutex*); void SubgraphThread (unsigned int, std::mutex*, std::mutex*, HighwayGraph*, WaypointQuadtree*, ElapsedTime*); void UserLogThread (unsigned int, std::mutex*, const double, const double); +void VtxFmtThread (unsigned int, std::vector*);