aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/basectx.h26
-rw-r--r--common/chain_utils.h4
-rw-r--r--common/context.cc4
-rw-r--r--common/hashlib.h4
-rw-r--r--common/nextpnr_types.h23
-rw-r--r--common/place_common.cc14
-rw-r--r--common/placer1.cc30
-rw-r--r--common/placer_heap.cc38
-rw-r--r--common/pybindings.cc14
-rw-r--r--common/router2.cc8
-rw-r--r--common/sdf.cc8
-rw-r--r--common/timing.cc14
-rw-r--r--common/timing_opt.cc6
-rw-r--r--common/util.h5
14 files changed, 101 insertions, 97 deletions
diff --git a/common/basectx.h b/common/basectx.h
index fccd12af..dd48c33c 100644
--- a/common/basectx.h
+++ b/common/basectx.h
@@ -59,29 +59,29 @@ struct BaseCtx
mutable StrRingBuffer log_strs;
// Project settings and config switches
- std::unordered_map<IdString, Property> settings;
+ dict<IdString, Property> settings;
// Placed nets and cells.
- std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets;
- std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells;
+ dict<IdString, std::unique_ptr<NetInfo>> nets;
+ dict<IdString, std::unique_ptr<CellInfo>> cells;
// Hierarchical (non-leaf) cells by full path
- std::unordered_map<IdString, HierarchicalCell> hierarchy;
+ dict<IdString, HierarchicalCell> hierarchy;
// This is the root of the above structure
IdString top_module;
// Aliases for nets, which may have more than one name due to assignments and hierarchy
- std::unordered_map<IdString, IdString> net_aliases;
+ dict<IdString, IdString> net_aliases;
// Top-level ports
- std::unordered_map<IdString, PortInfo> ports;
- std::unordered_map<IdString, CellInfo *> port_cells;
+ dict<IdString, PortInfo> ports;
+ dict<IdString, CellInfo *> port_cells;
// Floorplanning regions
- std::unordered_map<IdString, std::unique_ptr<Region>> region;
+ dict<IdString, std::unique_ptr<Region>> region;
// Context meta data
- std::unordered_map<IdString, Property> attrs;
+ dict<IdString, Property> attrs;
Context *as_ctx = nullptr;
@@ -186,10 +186,10 @@ struct BaseCtx
bool allUiReload = true;
bool frameUiReload = false;
- std::unordered_set<BelId> belUiReload;
- std::unordered_set<WireId> wireUiReload;
- std::unordered_set<PipId> pipUiReload;
- std::unordered_set<GroupId> groupUiReload;
+ pool<BelId> belUiReload;
+ pool<WireId> wireUiReload;
+ pool<PipId> pipUiReload;
+ pool<GroupId> groupUiReload;
void refreshUi() { allUiReload = true; }
diff --git a/common/chain_utils.h b/common/chain_utils.h
index 300d96a1..1bd95c9e 100644
--- a/common/chain_utils.h
+++ b/common/chain_utils.h
@@ -37,10 +37,10 @@ std::vector<CellChain> find_chains(const Context *ctx, F1 cell_type_predicate, F
{
std::set<IdString> chained;
std::vector<CellChain> chains;
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
if (chained.find(cell.first) != chained.end())
continue;
- CellInfo *ci = cell.second;
+ CellInfo *ci = cell.second.get();
if (cell_type_predicate(ctx, ci)) {
CellInfo *start = ci;
CellInfo *prev_start = ci;
diff --git a/common/context.cc b/common/context.cc
index 05c1e094..115b333a 100644
--- a/common/context.cc
+++ b/common/context.cc
@@ -389,8 +389,8 @@ struct FixupHierarchyWorker
// Update hierarchy structure for nets and cells that have hiercell set
void rebuild_hierarchy()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->hierpath == IdString())
ci->hierpath = ctx->top_module;
auto &hc = ctx->hierarchy.at(ci->hierpath);
diff --git a/common/hashlib.h b/common/hashlib.h
index 48db024f..30fefc65 100644
--- a/common/hashlib.h
+++ b/common/hashlib.h
@@ -339,6 +339,10 @@ template <typename K, typename T, typename OPS> class dict
}
public:
+ using key_type = K;
+ using mapped_type = T;
+ using value_type = std::pair<K, T>;
+
class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
{
friend class dict;
diff --git a/common/nextpnr_types.h b/common/nextpnr_types.h
index 67e60c50..4770f8ae 100644
--- a/common/nextpnr_types.h
+++ b/common/nextpnr_types.h
@@ -28,6 +28,7 @@
#include <unordered_set>
#include "archdefs.h"
+#include "hashlib.h"
#include "nextpnr_base_types.h"
#include "nextpnr_namespaces.h"
#include "property.h"
@@ -56,9 +57,9 @@ struct Region
bool constr_wires = false;
bool constr_pips = false;
- std::unordered_set<BelId> bels;
- std::unordered_set<WireId> wires;
- std::unordered_set<Loc> piplocs;
+ pool<BelId> bels;
+ pool<WireId> wires;
+ pool<Loc> piplocs;
};
struct PipMap
@@ -128,10 +129,10 @@ struct NetInfo : ArchNetInfo
PortRef driver;
std::vector<PortRef> users;
- std::unordered_map<IdString, Property> attrs;
+ dict<IdString, Property> attrs;
// wire -> uphill_pip
- std::unordered_map<WireId, PipMap> wires;
+ dict<WireId, PipMap> wires;
std::vector<IdString> aliases; // entries in net_aliases that point to this net
@@ -159,8 +160,8 @@ struct CellInfo : ArchCellInfo
IdString name, type, hierpath;
int32_t udata;
- std::unordered_map<IdString, PortInfo> ports;
- std::unordered_map<IdString, Property> attrs, params;
+ dict<IdString, PortInfo> ports;
+ dict<IdString, Property> attrs, params;
BelId bel;
PlaceStrength belStrength = STRENGTH_NONE;
@@ -232,13 +233,13 @@ struct HierarchicalCell
{
IdString name, type, parent, fullpath;
// Name inside cell instance -> global name
- std::unordered_map<IdString, IdString> leaf_cells, nets;
+ dict<IdString, IdString> leaf_cells, nets;
// Global name -> name inside cell instance
- std::unordered_map<IdString, IdString> leaf_cells_by_gname, nets_by_gname;
+ dict<IdString, IdString> leaf_cells_by_gname, nets_by_gname;
// Cell port to net
- std::unordered_map<IdString, HierarchicalPort> ports;
+ dict<IdString, HierarchicalPort> ports;
// Name inside cell instance -> global name
- std::unordered_map<IdString, IdString> hier_cells;
+ dict<IdString, IdString> hier_cells;
};
NEXTPNR_NAMESPACE_END
diff --git a/common/place_common.cc b/common/place_common.cc
index 7cbeca65..ece47b5a 100644
--- a/common/place_common.cc
+++ b/common/place_common.cc
@@ -377,9 +377,9 @@ class ConstraintLegaliseWorker
public:
ConstraintLegaliseWorker(Context *ctx) : ctx(ctx)
{
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
if (cell.second->cluster != ClusterId())
- cluster2cells[cell.second->cluster].push_back(cell.second);
+ cluster2cells[cell.second->cluster].push_back(cell.second.get());
}
};
@@ -414,11 +414,11 @@ class ConstraintLegaliseWorker
int legalise_constraints()
{
log_info("Legalising relative constraints...\n");
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
oldLocations[cell.first] = ctx->getBelLocation(cell.second->bel);
}
- for (auto cell : sorted(ctx->cells)) {
- bool res = legalise_cell(cell.second);
+ for (auto &cell : ctx->cells) {
+ bool res = legalise_cell(cell.second.get());
if (!res) {
log_error("failed to place chain starting at cell '%s'\n", cell.first.c_str(ctx));
return -1;
@@ -434,8 +434,8 @@ class ConstraintLegaliseWorker
}
}
auto score = print_stats("replacing ripped up cells");
- for (auto cell : sorted(ctx->cells))
- if (get_constraints_distance(ctx, cell.second) != 0)
+ for (auto &cell : ctx->cells)
+ if (get_constraints_distance(ctx, cell.second.get()) != 0)
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
ctx->nameOfBel(cell.second->bel));
return score;
diff --git a/common/placer1.cc b/common/placer1.cc
index a3e7a696..f9cef92f 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -88,7 +88,7 @@ class SAPlacer
diameter = std::max(max_x, max_y) + 1;
std::unordered_set<IdString> cell_types_in_use;
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
IdString cell_type = cell.second->type;
cell_types_in_use.insert(cell_type);
}
@@ -108,8 +108,8 @@ class SAPlacer
net.second->udata = n++;
net_by_udata.push_back(net.second.get());
}
- for (auto &region : sorted(ctx->region)) {
- Region *r = region.second;
+ for (auto &region : ctx->region) {
+ Region *r = region.second.get();
BoundingBox bb;
if (r->constr_bels) {
bb.x0 = std::numeric_limits<int>::max();
@@ -360,12 +360,12 @@ class SAPlacer
// Only increase temperature if something was moved
autoplaced.clear();
chain_basis.clear();
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
if (cell.second->belStrength <= STRENGTH_STRONG && cell.second->cluster != ClusterId() &&
- ctx->getClusterRootCell(cell.second->cluster) == cell.second)
- chain_basis.push_back(cell.second);
+ ctx->getClusterRootCell(cell.second->cluster) == cell.second.get())
+ chain_basis.push_back(cell.second.get());
else if (cell.second->belStrength < STRENGTH_STRONG)
- autoplaced.push_back(cell.second);
+ autoplaced.push_back(cell.second.get());
}
// temp = post_legalise_temp;
// diameter = std::min<int>(M, diameter * post_legalise_dia_scale);
@@ -421,8 +421,8 @@ class SAPlacer
}
}
}
- for (auto cell : sorted(ctx->cells))
- if (get_constraints_distance(ctx, cell.second) != 0)
+ for (auto &cell : ctx->cells)
+ if (get_constraints_distance(ctx, cell.second.get()) != 0)
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
ctx->nameOfBel(cell.second->bel));
timing_analysis(ctx);
@@ -831,8 +831,8 @@ class SAPlacer
// Set up the cost maps
void setup_costs()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ignore_net(ni))
continue;
net_bounds[ni->udata] = get_net_bounds(ni);
@@ -1118,8 +1118,8 @@ class SAPlacer
// Build the cell port -> user index
void build_port_index()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
for (size_t i = 0; i < ni->users.size(); i++) {
auto &usr = ni->users.at(i);
fast_port_to_user[&(usr.cell->ports.at(usr.port))] = i;
@@ -1135,8 +1135,8 @@ class SAPlacer
{
total_net_share = 0;
nets_by_tile.resize(max_x + 1, std::vector<std::unordered_map<IdString, int>>(max_y + 1));
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (int(ci->ports.size()) > large_cell_thresh)
continue;
Loc loc = ctx->getBelLocation(ci->bel);
diff --git a/common/placer_heap.cc b/common/placer_heap.cc
index 2f7c7ccb..c26e1556 100644
--- a/common/placer_heap.cc
+++ b/common/placer_heap.cc
@@ -146,9 +146,9 @@ class HeAPPlacer
tmg.setup_only = true;
tmg.setup();
- for (auto cell : sorted(ctx->cells))
+ for (auto &cell : ctx->cells)
if (cell.second->cluster != ClusterId())
- cluster2cells[cell.second->cluster].push_back(cell.second);
+ cluster2cells[cell.second->cluster].push_back(cell.second.get());
}
bool place()
@@ -283,8 +283,8 @@ class HeAPPlacer
stalled = 0;
// Save solution
solution.clear();
- for (auto cell : sorted(ctx->cells)) {
- solution.emplace_back(cell.second, cell.second->bel, cell.second->belStrength);
+ for (auto &cell : ctx->cells) {
+ solution.emplace_back(cell.second.get(), cell.second->bel, cell.second->belStrength);
}
} else {
++stalled;
@@ -311,10 +311,10 @@ class HeAPPlacer
ctx->bindBel(bel, cell, strength);
}
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
if (cell.second->bel == BelId())
log_error("Found unbound cell %s\n", cell.first.c_str(ctx));
- if (ctx->getBoundBelCell(cell.second->bel) != cell.second)
+ if (ctx->getBoundBelCell(cell.second->bel) != cell.second.get())
log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx));
if (ctx->debug)
log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel));
@@ -450,7 +450,7 @@ class HeAPPlacer
std::unordered_set<IdString> cell_types_in_use;
std::unordered_set<BelBucketId> buckets_in_use;
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
IdString cell_type = cell.second->type;
cell_types_in_use.insert(cell_type);
BelBucketId bucket = ctx->getBelBucketForCellType(cell_type);
@@ -465,8 +465,8 @@ class HeAPPlacer
}
// Determine bounding boxes of region constraints
- for (auto &region : sorted(ctx->region)) {
- Region *r = region.second;
+ for (auto &region : ctx->region) {
+ Region *r = region.second.get();
BoundingBox bb;
if (r->constr_bels) {
bb.x0 = std::numeric_limits<int>::max();
@@ -539,8 +539,8 @@ class HeAPPlacer
ctx->shuffle(t.second.begin(), t.second.end());
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->bel != BelId()) {
Loc loc = ctx->getBelLocation(ci->bel);
cell_locs[cell.first].x = loc.x;
@@ -591,7 +591,7 @@ class HeAPPlacer
cell_locs[cell.first].global = ctx->getBelGlobalBuf(bel);
// FIXME
- if (has_connectivity(cell.second) && !cfg.ioBufTypes.count(ci->type)) {
+ if (has_connectivity(cell.second.get()) && !cfg.ioBufTypes.count(ci->type)) {
bels_used.insert(bel);
place_cells.push_back(ci);
placed = true;
@@ -617,7 +617,7 @@ class HeAPPlacer
int row = 0;
solve_cells.clear();
// First clear the udata of all cells
- for (auto cell : sorted(ctx->cells))
+ for (auto &cell : ctx->cells)
cell.second->udata = dont_solve;
// Then update cells to be placed, which excludes cell children
for (auto cell : place_cells) {
@@ -671,8 +671,8 @@ class HeAPPlacer
es.reset();
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
if (ni->users.empty())
@@ -783,8 +783,8 @@ class HeAPPlacer
wirelen_t total_hpwl()
{
wirelen_t hpwl = 0;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
CellLocation &drvloc = cell_locs.at(ni->driver.cell->name);
@@ -809,8 +809,8 @@ class HeAPPlacer
auto startt = std::chrono::high_resolution_clock::now();
// Unbind all cells placed in this solution
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->bel != BelId() &&
(ci->udata != dont_solve ||
(ci->cluster != ClusterId() && ctx->getClusterRootCell(ci->cluster)->udata != dont_solve)))
diff --git a/common/pybindings.cc b/common/pybindings.cc
index 504074e1..00ebe66e 100644
--- a/common/pybindings.cc
+++ b/common/pybindings.cc
@@ -164,10 +164,10 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
.def("maxFallDelay", &DelayQuad::maxFallDelay)
.def("delayPair", &DelayQuad::delayPair);
- typedef std::unordered_map<IdString, Property> AttrMap;
- typedef std::unordered_map<IdString, PortInfo> PortMap;
- typedef std::unordered_map<IdString, IdString> IdIdMap;
- typedef std::unordered_map<IdString, std::unique_ptr<Region>> RegionMap;
+ typedef dict<IdString, Property> AttrMap;
+ typedef dict<IdString, PortInfo> PortMap;
+ typedef dict<IdString, IdString> IdIdMap;
+ typedef dict<IdString, std::unique_ptr<Region>> RegionMap;
py::class_<BaseCtx>(m, "BaseCtx");
@@ -218,9 +218,9 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
pass_through<PortType>>::def_wrap(pi_cls, "type");
typedef std::vector<PortRef> PortRefVector;
- typedef std::unordered_map<WireId, PipMap> WireMap;
- typedef std::unordered_set<BelId> BelSet;
- typedef std::unordered_set<WireId> WireSet;
+ typedef dict<WireId, PipMap> WireMap;
+ typedef pool<BelId> BelSet;
+ typedef pool<WireId> WireSet;
auto ni_cls = py::class_<ContextualWrapper<NetInfo &>>(m, "NetInfo");
readwrite_wrapper<NetInfo &, decltype(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>,
diff --git a/common/router2.cc b/common/router2.cc
index 2156ce28..b0f53ce1 100644
--- a/common/router2.cc
+++ b/common/router2.cc
@@ -131,8 +131,8 @@ struct Router2
nets.resize(ctx->nets.size());
nets_by_udata.resize(ctx->nets.size());
size_t i = 0;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
ni->udata = i;
nets_by_udata.at(i) = ni;
nets.at(i).arcs.resize(ni->users.size());
@@ -231,8 +231,8 @@ struct Router2
flat_wires.push_back(pwd);
}
- for (auto net_pair : sorted(ctx->nets)) {
- auto *net = net_pair.second;
+ for (auto &net_pair : ctx->nets) {
+ auto *net = net_pair.second.get();
auto &nd = nets.at(net->udata);
for (size_t usr = 0; usr < net->users.size(); usr++) {
auto &ad = nd.arcs.at(usr);
diff --git a/common/sdf.cc b/common/sdf.cc
index 5c3d0a5a..814bf09a 100644
--- a/common/sdf.cc
+++ b/common/sdf.cc
@@ -254,9 +254,9 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
return rf;
};
- for (auto cell : sorted(cells)) {
+ for (const auto &cell : cells) {
Cell sc;
- const CellInfo *ci = cell.second;
+ const CellInfo *ci = cell.second.get();
sc.instance = ci->name.str(this);
sc.celltype = ci->type.str(this);
for (auto port : ci->ports) {
@@ -313,8 +313,8 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
wr.cells.push_back(sc);
}
- for (auto net : sorted(nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
for (auto &usr : ni->users) {
diff --git a/common/timing.cc b/common/timing.cc
index ef5977de..b68ca35c 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -52,17 +52,17 @@ void TimingAnalyser::run()
void TimingAnalyser::init_ports()
{
// Per cell port structures
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
- for (auto port : sorted_ref(ci->ports)) {
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
+ for (auto &port : ci->ports) {
auto &data = ports[CellPortKey(ci->name, port.first)];
data.type = port.second.type;
data.cell_port = CellPortKey(ci->name, port.first);
}
}
// Cell port to net port mapping
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr)
ports[CellPortKey(ni->driver)].net_port = NetPortKey(ni->name);
for (size_t i = 0; i < ni->users.size(); i++)
@@ -138,8 +138,8 @@ void TimingAnalyser::get_cell_delays()
void TimingAnalyser::get_route_delays()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId())
continue;
for (auto &usr : ni->users) {
diff --git a/common/timing_opt.cc b/common/timing_opt.cc
index 854cbc5b..2659f04e 100644
--- a/common/timing_opt.cc
+++ b/common/timing_opt.cc
@@ -68,8 +68,8 @@ class TimingOptimiser
void setup_delay_limits()
{
max_net_delay.clear();
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
for (auto usr : ni->users) {
@@ -239,7 +239,7 @@ class TimingOptimiser
std::vector<std::pair<NetInfo *, int>> crit_nets;
std::vector<IdString> netnames;
std::transform(ctx->nets.begin(), ctx->nets.end(), std::back_inserter(netnames),
- [](const std::pair<const IdString, std::unique_ptr<NetInfo>> &kv) { return kv.first; });
+ [](const std::pair<IdString, std::unique_ptr<NetInfo>> &kv) { return kv.first; });
ctx->sorted_shuffle(netnames);
for (auto net : netnames) {
if (crit_nets.size() >= max_count)
diff --git a/common/util.h b/common/util.h
index 540646c7..b3e8cbf0 100644
--- a/common/util.h
+++ b/common/util.h
@@ -55,7 +55,7 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string
};
template <typename KeyType>
-std::string str_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, std::string def = "")
+std::string str_or_default(const dict<KeyType, Property> &ct, const KeyType &key, std::string def = "")
{
auto found = ct.find(key);
if (found == ct.end())
@@ -78,8 +78,7 @@ template <typename Container, typename KeyType> int int_or_default(const Contain
return std::stoi(found->second);
};
-template <typename KeyType>
-int int_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, int def = 0)
+template <typename KeyType> int int_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int def = 0)
{
auto found = ct.find(key);
if (found == ct.end())