From ed8e3c83d97d775f912266c701ebf17e416cc50b Mon Sep 17 00:00:00 2001
From: "D. Shah" <dave@ds0.me>
Date: Thu, 4 Feb 2021 11:21:16 +0000
Subject: Add default implementation of some range-returning functions

Signed-off-by: D. Shah <dave@ds0.me>
---
 common/nextpnr.h | 32 +++++++++++++++++++++++++++-----
 ecp5/arch.h      | 12 ------------
 2 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/common/nextpnr.h b/common/nextpnr.h
index e2e87cbc..a97deaa3 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -1012,6 +1012,19 @@ struct BaseCtx
     void attributesToArchInfo();
 };
 
+// For several functions; such as bel/wire/pip attributes; the trivial implementation is to return an empty vector
+// But an arch might want to do something fancy with a custom range type that doesn't provide a constructor
+// So some cursed C++ is needed to return an empty object if possible; or error out if not; is needed
+template <typename Tc> typename std::enable_if<std::is_constructible<Tc>::value, Tc>::type empty_if_possible()
+{
+    return Tc();
+}
+template <typename Tc> typename std::enable_if<!std::is_constructible<Tc>::value, Tc>::type empty_if_possible()
+{
+    NPNR_ASSERT_FALSE("attempting to use default implementation of range-returning function with range type lacking "
+                      "default constructor!");
+}
+
 template <typename R> struct ArchBase : BaseCtx
 {
     // --------------------------------------------------------------
@@ -1019,7 +1032,7 @@ template <typename R> struct ArchBase : BaseCtx
 
     // Basic config
     virtual std::string getChipName() const = 0;
-    virtual IdString archId() const { id(STRINGIFY(ARCHNAME)); }
+    virtual IdString archId() const { return id(STRINGIFY(ARCHNAME)); }
     virtual int getGridDimX() const = 0;
     virtual int getGridDimY() const = 0;
     virtual int getTileBelDimZ(int x, int y) const = 0;
@@ -1063,7 +1076,10 @@ template <typename R> struct ArchBase : BaseCtx
     }
     virtual CellInfo *getConflictingBelCell(BelId bel) const { return getBoundBelCell(bel); }
     virtual IdString getBelType(BelId bel) const = 0;
-    virtual typename R::BelAttrsRange getBelAttrs(BelId bel) const = 0;
+    virtual typename R::BelAttrsRange getBelAttrs(BelId bel) const
+    {
+        return empty_if_possible<typename R::BelAttrsRange>();
+    }
     virtual WireId getBelPinWire(BelId bel, IdString pin) const = 0;
     virtual PortType getBelPinType(BelId bel, IdString pin) const = 0;
 
@@ -1072,7 +1088,10 @@ template <typename R> struct ArchBase : BaseCtx
     virtual WireId getWireByName(IdStringList name) const = 0;
     virtual IdStringList getWireName(WireId wire) const = 0;
     virtual IdString getWireType(WireId wire) const { return IdString(); }
-    virtual typename R::WireAttrsRange getWireAttrs(WireId) const = 0;
+    virtual typename R::WireAttrsRange getWireAttrs(WireId) const
+    {
+        return empty_if_possible<typename R::WireAttrsRange>();
+    }
     virtual uint32_t getWireChecksum(WireId wire) const { return uint32_t(std::hash<WireId>()(wire)); }
     virtual typename R::DownhillPipRange getPipsDownhill(WireId wire) const = 0;
     virtual typename R::UphillPipRange getPipsUphill(WireId wire) const = 0;
@@ -1123,7 +1142,10 @@ template <typename R> struct ArchBase : BaseCtx
     virtual PipId getPipByName(IdStringList name) const = 0;
     virtual IdStringList getPipName(PipId pip) const = 0;
     virtual IdString getPipType(PipId pip) const { return IdString(); }
-    virtual typename R::PipAttrsRange getPipAttrs(PipId) const = 0;
+    virtual typename R::PipAttrsRange getPipAttrs(PipId) const
+    {
+        return empty_if_possible<typename R::PipAttrsRange>();
+    }
     virtual uint32_t getPipChecksum(PipId pip) const { return uint32_t(std::hash<PipId>()(pip)); }
     virtual void bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
     {
@@ -1171,7 +1193,7 @@ template <typename R> struct ArchBase : BaseCtx
     virtual IdStringList getGroupName(GroupId group) const { return IdStringList(); };
     virtual delay_t estimateDelay(WireId src, WireId dst) const = 0;
     virtual ArcBounds getRouteBoundingBox(WireId src, WireId dst) const = 0;
-    virtual typename R::AllGroupsRange getGroups() const = 0;
+    virtual typename R::AllGroupsRange getGroups() const { return empty_if_possible<typename R::AllGroupsRange>(); }
     // Default implementation of these assumes no groups so never called
     virtual typename R::GroupBelsRange getGroupBels(GroupId group) const { NPNR_ASSERT_FALSE("unreachable"); };
     virtual typename R::GroupWiresRange getGroupWires(GroupId group) const { NPNR_ASSERT_FALSE("unreachable"); };
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 705a9ebb..5ea5206b 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -602,12 +602,6 @@ struct Arch : ArchBase<ArchRanges>
         return id;
     }
 
-    std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId) const override
-    {
-        std::vector<std::pair<IdString, std::string>> ret;
-        return ret;
-    }
-
     WireId getBelPinWire(BelId bel, IdString pin) const override;
 
     BelPinRange getWireBelPins(WireId wire) const override
@@ -704,12 +698,6 @@ struct Arch : ArchBase<ArchRanges>
     PipId getPipByName(IdStringList name) const override;
     IdStringList getPipName(PipId pip) const override;
 
-    std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId) const
-    {
-        std::vector<std::pair<IdString, std::string>> ret;
-        return ret;
-    }
-
     uint32_t getPipChecksum(PipId pip) const override { return pip.index; }
 
     void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override
-- 
cgit v1.2.3