Skip to content

Commit 9ea540a

Browse files
authored
Add custom std::formatters for many classes (#307)
* Add custom formatters for `Agent` and `Street` classes * Add custom formatter also for `TrafficLight`-related classes
1 parent 75325a5 commit 9ea540a

File tree

7 files changed

+136
-92
lines changed

7 files changed

+136
-92
lines changed

src/dsf/dsf.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
static constexpr uint8_t DSF_VERSION_MAJOR = 3;
88
static constexpr uint8_t DSF_VERSION_MINOR = 1;
9-
static constexpr uint8_t DSF_VERSION_PATCH = 0;
9+
static constexpr uint8_t DSF_VERSION_PATCH = 1;
1010

1111
static auto const DSF_VERSION =
1212
std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH);

src/dsf/headers/Agent.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
#include <cassert>
1818
#include <concepts>
19+
#include <format>
1920
#include <limits>
2021
#include <optional>
2122
#include <stdexcept>
23+
#include <string>
2224
#include <vector>
2325

2426
namespace dsf {
@@ -118,3 +120,24 @@ namespace dsf {
118120
bool isRandom() const;
119121
};
120122
}; // namespace dsf
123+
124+
template <>
125+
struct std::formatter<dsf::Agent> {
126+
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
127+
template <typename FormatContext>
128+
auto format(const dsf::Agent& agent, FormatContext& ctx) const {
129+
auto const strItinerary = agent.trip().empty() ? std::string("RANDOM")
130+
: std::to_string(agent.itineraryId());
131+
return std::format_to(ctx.out(),
132+
"Agent (srcNode {} - it {}) spawn time {} - free time {}: {} "
133+
"-> {} ({} m/s - {} m)",
134+
agent.srcNodeId().value_or(-1),
135+
strItinerary,
136+
agent.spawnTime(),
137+
agent.freeTime(),
138+
agent.streetId().value_or(-1),
139+
agent.nextStreetId().value_or(-1),
140+
agent.speed(),
141+
agent.distance());
142+
}
143+
};

src/dsf/headers/RoadDynamics.hpp

Lines changed: 42 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ namespace dsf {
9494
/// @brief Evolve the agents.
9595
/// @details Puts all new agents on a street, if possible, decrements all delays
9696
/// and increments all travel times.
97-
void m_evolveAgent(std::unique_ptr<Agent> const& pAgent);
97+
// void m_evolveAgent(std::unique_ptr<Agent> const& pAgent);
9898

9999
void m_trafficlightSingleTailOptimizer(double const& beta,
100100
std::optional<std::ofstream>& logStream);
@@ -614,8 +614,8 @@ namespace dsf {
614614
}
615615

616616
if (possibleMoves.empty()) {
617-
throw std::runtime_error(std::format(
618-
"No possible moves for agent {} at node {}.", pAgent->id(), nodeId));
617+
throw std::runtime_error(
618+
std::format("No possible moves for agent {} at node {}.", *pAgent, nodeId));
619619
}
620620

621621
if (possibleMoves.size() == 1) {
@@ -743,21 +743,15 @@ namespace dsf {
743743
auto const timeDiff{this->time() - pAgentTemp->freeTime()};
744744
if (timeDiff > 120) {
745745
overtimed = true;
746-
Logger::warning(std::format(
747-
"Time {} - Agent ({} -> {}) currently on {} ({} -> {}), targetting {} "
748-
"({} turn - "
749-
"Traffic "
750-
"Light? {}), has been still for more than 120 seconds ({} seconds)",
751-
this->time(),
752-
pAgentTemp->srcNodeId().value_or(-1),
753-
this->m_itineraries.at(pAgentTemp->itineraryId())->destination(),
754-
pStreet->id(),
755-
pStreet->source(),
756-
pStreet->target(),
757-
pAgentTemp->nextStreetId().value_or(-1),
758-
directionToString.at(pStreet->laneMapping().at(queueIndex)),
759-
this->graph().node(pStreet->target())->isTrafficLight(),
760-
timeDiff));
746+
Logger::warning(
747+
std::format("Time {} - {} currently on {} ({} turn - Traffic Light? {}), "
748+
"has been still for more than 120 seconds ({} seconds)",
749+
this->time(),
750+
*pAgentTemp,
751+
*pStreet,
752+
directionToString.at(pStreet->laneMapping().at(queueIndex)),
753+
this->graph().node(pStreet->target())->isTrafficLight(),
754+
timeDiff));
761755
}
762756
}
763757
pAgentTemp->setSpeed(0.);
@@ -946,27 +940,24 @@ namespace dsf {
946940
continue;
947941
}
948942
if (!pAgentTemp->streetId().has_value()) {
949-
Logger::error(std::format("Agent {} has no street id", pAgentTemp->id()));
943+
Logger::error(std::format("{} has no street id", *pAgentTemp));
950944
}
951945
auto const& nextStreet{this->graph().edge(pAgentTemp->nextStreetId().value())};
952946
if (nextStreet->isFull()) {
953947
if (overtimed) {
954-
Logger::warning(std::format(
955-
"Skipping agent emission from street {} -> {} due to full next street "
956-
"{} - strId {} ({}/{})",
957-
pStreet->source(),
958-
pStreet->target(),
959-
nextStreet->id(),
960-
nextStreet->strId().value_or("None"),
961-
nextStreet->nAgents(),
962-
nextStreet->capacity()));
948+
Logger::warning(
949+
std::format("Skipping agent emission from street {} -> {} due to full "
950+
"next street: {}",
951+
pStreet->source(),
952+
pStreet->target(),
953+
*nextStreet));
963954
} else {
964-
Logger::debug(std::format(
965-
"Skipping agent emission from street {} -> {} due to full next street "
966-
"{}",
967-
pStreet->source(),
968-
pStreet->target(),
969-
nextStreet->id()));
955+
Logger::debug(
956+
std::format("Skipping agent emission from street {} -> {} due to full "
957+
"next street: {}",
958+
pStreet->source(),
959+
pStreet->target(),
960+
*nextStreet));
970961
}
971962
continue;
972963
}
@@ -1012,7 +1003,7 @@ namespace dsf {
10121003
auto& pAgent{it->second};
10131004
auto const& nextStreet{this->graph().edge(pAgent->nextStreetId().value())};
10141005
if (nextStreet->isFull()) {
1015-
Logger::debug(std::format("Next street {} is full", nextStreet->id()));
1006+
Logger::debug(std::format("Next street is full: {}", *nextStreet));
10161007
if (m_forcePriorities) {
10171008
Logger::debug(
10181009
std::format("Forcing priority from intersection {} on street {}",
@@ -1029,12 +1020,11 @@ namespace dsf {
10291020
std::ceil(nextStreet->length() / pAgent->speed()));
10301021
Logger::debug(std::format(
10311022
"An agent at time {} has been dequeued from intersection {} and "
1032-
"enqueued on street {} with speed {} and free time {}",
1023+
"enqueued on street {}: {}",
10331024
this->time(),
10341025
pNode->id(),
10351026
nextStreet->id(),
1036-
pAgent->speed(),
1037-
pAgent->freeTime()));
1027+
*pAgent));
10381028
nextStreet->addAgent(std::move(pAgent));
10391029
it = intersection.agents().erase(it);
10401030
break;
@@ -1064,12 +1054,11 @@ namespace dsf {
10641054
std::ceil(nextStreet->length() / pAgent->speed()));
10651055
Logger::debug(
10661056
std::format("An agent at time {} has been dequeued from roundabout {} and "
1067-
"enqueued on street {} with speed {} and free time {}",
1057+
"enqueued on street {}: {}",
10681058
this->time(),
10691059
pNode->id(),
10701060
nextStreet->id(),
1071-
pAgent->speed(),
1072-
pAgent->freeTime()));
1061+
*pAgent));
10731062
nextStreet->addAgent(std::move(pAgent));
10741063
} else {
10751064
return;
@@ -1078,11 +1067,11 @@ namespace dsf {
10781067
}
10791068
}
10801069

1081-
template <typename delay_t>
1082-
requires(is_numeric_v<delay_t>)
1083-
void RoadDynamics<delay_t>::m_evolveAgent(std::unique_ptr<Agent> const& pAgent) {
1084-
// The "cost" of enqueuing is one time unit, so we consider it as passed
1085-
}
1070+
// template <typename delay_t>
1071+
// requires(is_numeric_v<delay_t>)
1072+
// void RoadDynamics<delay_t>::m_evolveAgent(std::unique_ptr<Agent> const& pAgent) {
1073+
// // The "cost" of enqueuing is one time unit, so we consider it as passed
1074+
// }
10861075

10871076
template <typename delay_t>
10881077
requires(is_numeric_v<delay_t>)
@@ -1512,11 +1501,8 @@ namespace dsf {
15121501
this->graph().edge(pAgent->nextStreetId().value())}; // next street
15131502
if (nextStreet->isFull()) {
15141503
++itAgent;
1515-
Logger::debug(
1516-
std::format("Skipping agent {} on node {} due to full initial street {}",
1517-
pAgent->id(),
1518-
srcNode->id(),
1519-
nextStreet->id()));
1504+
Logger::debug(std::format(
1505+
"Skipping agent {} due to full input street {}", *pAgent, *nextStreet));
15201506
continue;
15211507
}
15221508
assert(srcNode->id() == nextStreet->source());
@@ -1872,12 +1858,11 @@ namespace dsf {
18721858
direction == Direction::RIGHTANDSTRAIGHT) {
18731859
auto const& pStreet{this->graph().edge(streetId)};
18741860
if (logStream.has_value()) {
1875-
*logStream << std::format("\tFree cycle ({}) for {} -> {}: {} {}\n",
1876-
directionToString[direction],
1861+
*logStream << std::format("\tFree cycle for {} -> {}: dir {} - {}\n",
18771862
pStreet->source(),
18781863
pStreet->target(),
1879-
freecycle.greenTime(),
1880-
freecycle.phase());
1864+
directionToString[direction],
1865+
freecycle);
18811866
}
18821867
cycle = freecycle;
18831868
}
@@ -1908,21 +1893,7 @@ namespace dsf {
19081893

19091894
tl.setCycles(cycles);
19101895
if (logStream.has_value()) {
1911-
std::string logMsg =
1912-
std::format("\tNew cycles for TL {} ({}):\n", tl.id(), tl.cycleTime());
1913-
for (auto const& [streetId, pair] : tl.cycles()) {
1914-
auto const& pStreet{this->graph().edge(streetId)};
1915-
logMsg +=
1916-
std::format("\t\tStreet {} -> {}: ", pStreet->source(), pStreet->target());
1917-
for (auto const& [direction, cycle] : pair) {
1918-
logMsg += std::format("{}= ({} {}) ",
1919-
directionToString[direction],
1920-
cycle.greenTime(),
1921-
cycle.phase());
1922-
}
1923-
logMsg += '\n';
1924-
}
1925-
*logStream << logMsg << '\n';
1896+
*logStream << std::format("\nNew cycles for {}", tl);
19261897
}
19271898
}
19281899
if (logStream.has_value()) {
@@ -1995,21 +1966,7 @@ namespace dsf {
19951966
(pStreet->maxSpeed() * (1. - 0.6 * pStreet->density(true))));
19961967
optimizedNodes.insert(sourceId);
19971968
if (logStream.has_value()) {
1998-
std::string logMsg =
1999-
std::format("\tNew cycles for TL {} ({}):\n", tl.id(), tl.cycleTime());
2000-
for (auto const& [streetId, pair] : tl.cycles()) {
2001-
auto const& pStreet{this->graph().edge(streetId)};
2002-
logMsg += std::format(
2003-
"\t\tStreet {} -> {}: ", pStreet->source(), pStreet->target());
2004-
for (auto const& [direction, cycle] : pair) {
2005-
logMsg += std::format("{}= ({} {}) ",
2006-
directionToString[direction],
2007-
cycle.greenTime(),
2008-
cycle.phase());
2009-
}
2010-
logMsg += '\n';
2011-
}
2012-
*logStream << logMsg << '\n';
1969+
*logStream << std::format("\nNew cycles for {}", tl);
20131970
}
20141971
}
20151972
}

src/dsf/headers/Street.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,23 @@ namespace dsf {
216216
};
217217

218218
}; // namespace dsf
219+
220+
template <>
221+
struct std::formatter<dsf::Street> {
222+
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
223+
template <typename fmtContext>
224+
auto format(const dsf::Street& street, fmtContext& ctx) const {
225+
return std::format_to(
226+
ctx.out(),
227+
"Street \"{}\" ({}: {} -> {}). {} m - {} m/s - {} lanes - {} agents ({} exiting)",
228+
street.name(),
229+
street.id(),
230+
street.nodePair().first,
231+
street.nodePair().second,
232+
street.length(),
233+
street.maxSpeed(),
234+
street.nLanes(),
235+
street.nAgents(),
236+
street.nExitingAgents());
237+
}
238+
};

src/dsf/headers/TrafficLight.hpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#pragma once
1111

1212
#include "Intersection.hpp"
13+
#include "../utility/Typedef.hpp"
14+
15+
#include <format>
16+
#include <string>
1317

1418
namespace dsf {
1519
class TrafficLightCycle {
@@ -143,6 +147,7 @@ namespace dsf {
143147
cycles() const {
144148
return m_cycles;
145149
}
150+
inline Delay counter() const { return m_counter; }
146151
/// @brief Returns true if all the cycles are set to their default values
147152
bool isDefault() const;
148153
/// @brief Returns true if the traffic light is green for a street and a direction
@@ -159,4 +164,41 @@ namespace dsf {
159164
void resetCycles();
160165
inline bool isTrafficLight() const noexcept { return true; }
161166
};
162-
} // namespace dsf
167+
} // namespace dsf
168+
169+
template <>
170+
struct std::formatter<dsf::TrafficLightCycle> {
171+
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
172+
template <typename FormatContext>
173+
auto format(const dsf::TrafficLightCycle& cycle, FormatContext& ctx) const {
174+
return std::format_to(ctx.out(),
175+
"TrafficLightCycle (green time: {} - phase shift: {})",
176+
cycle.greenTime(),
177+
cycle.phase());
178+
}
179+
};
180+
181+
template <>
182+
struct std::formatter<dsf::TrafficLight> {
183+
constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
184+
template <typename FormatContext>
185+
auto format(const dsf::TrafficLight& tl, FormatContext& ctx) const {
186+
std::string strCycles;
187+
for (auto const& [streetId, cycles] : tl.cycles()) {
188+
std::string strStreetCycles{std::format("\tStreet {}:\n", streetId)};
189+
for (auto const& [direction, cycle] : cycles) {
190+
strStreetCycles += std::format(
191+
"\t\t- dir {}: {}\n", dsf::directionToString.at(direction), cycle);
192+
}
193+
strCycles += strStreetCycles;
194+
}
195+
return std::format_to(
196+
ctx.out(),
197+
"TrafficLight \"{}\" ({}): cycle time {} - counter {}. Cycles:\n{}",
198+
tl.name(),
199+
tl.id(),
200+
tl.cycleTime(),
201+
tl.counter(),
202+
strCycles);
203+
}
204+
};

src/dsf/sources/Agent.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "../headers/Agent.hpp"
22

3+
#include <format>
4+
35
namespace dsf {
46
Agent::Agent(Time const& spawnTime,
57
std::optional<Id> itineraryId,
@@ -82,4 +84,4 @@ namespace dsf {
8284
double Agent::speed() const { return m_speed; }
8385
double Agent::distance() const { return m_distance; }
8486
bool Agent::isRandom() const { return m_trip.empty(); }
85-
} // namespace dsf
87+
} // namespace dsf

src/dsf/utility/Logger.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
#include <string>
1010
#include <set>
1111

12-
static std::string buildMessage(const std::string& type,
13-
const std::string& message,
14-
const std::source_location& location,
15-
bool verbose) {
12+
static inline std::string buildMessage(const std::string& type,
13+
const std::string& message,
14+
const std::source_location& location,
15+
bool verbose) {
1616
if (verbose) {
1717
return std::format("{} ({}:{}) \'{}\': {}",
1818
type,

0 commit comments

Comments
 (0)