Move decodable lists bits as a non-template class to save flash (#36253)

Co-authored-by: Andrei Litvin <andreilitvin@google.com>
diff --git a/src/app/data-model/DecodableList.h b/src/app/data-model/DecodableList.h
index bff54ca..b05db43 100644
--- a/src/app/data-model/DecodableList.h
+++ b/src/app/data-model/DecodableList.h
@@ -27,6 +27,68 @@
 namespace app {
 namespace DataModel {
 
+namespace detail {
+
+/*
+ * Base class of DecodableList to minimize template usage
+ */
+class DecodableListBase
+{
+public:
+    DecodableListBase() { ClearReader(); }
+
+    /*
+     * @brief
+     *
+     * This call stores a TLV reader positioned on the list this class is to manage.
+     *
+     * Specifically, the passed-in reader should be pointing into the list just after
+     * having called `OpenContainer` on the list element.
+     */
+    void SetReader(const TLV::TLVReader & reader) { mReader = reader; }
+
+    /*
+     * @brief
+     *
+     * This call clears the TLV reader managed by this class, so it can be reused.
+     */
+    void ClearReader() { mReader.Init(nullptr, 0); }
+
+    /*
+     * Compute the size of the list. This can fail if the TLV is malformed. If
+     * this succeeds, that does not guarantee that the individual items can be
+     * successfully decoded; consumers should check Iterator::GetStatus() when
+     * actually decoding them. If there is no list then the size is considered
+     * to be zero.
+     */
+    CHIP_ERROR ComputeSize(size_t * size) const
+    {
+        if (mReader.GetContainerType() == TLV::kTLVType_NotSpecified)
+        {
+            *size = 0;
+            return CHIP_NO_ERROR;
+        }
+
+        return mReader.CountRemainingInContainer(size);
+    }
+
+    CHIP_ERROR Decode(TLV::TLVReader & reader)
+    {
+        VerifyOrReturnError(reader.GetType() == TLV::kTLVType_Array, CHIP_ERROR_SCHEMA_MISMATCH);
+        TLV::TLVType type;
+        ReturnErrorOnFailure(reader.EnterContainer(type));
+        SetReader(reader);
+        ReturnErrorOnFailure(reader.ExitContainer(type));
+        return CHIP_NO_ERROR;
+    }
+
+protected:
+    TLV::TLVReader mReader;
+    chip::Optional<FabricIndex> mFabricIndex;
+};
+
+} // namespace detail
+
 /*
  * @brief
  *
@@ -47,30 +109,13 @@
  *
  */
 template <typename T>
-class DecodableList
+class DecodableList : public detail::DecodableListBase
 {
 public:
-    DecodableList() { ClearReader(); }
+    DecodableList() {}
 
     static constexpr bool kIsFabricScoped = DataModel::IsFabricScoped<T>::value;
 
-    /*
-     * @brief
-     *
-     * This call stores a TLV reader positioned on the list this class is to manage.
-     *
-     * Specifically, the passed-in reader should be pointing into the list just after
-     * having called `OpenContainer` on the list element.
-     */
-    void SetReader(const TLV::TLVReader & reader) { mReader = reader; }
-
-    /*
-     * @brief
-     *
-     * This call clears the TLV reader managed by this class, so it can be reused.
-     */
-    void ClearReader() { mReader.Init(nullptr, 0); }
-
     template <typename T0 = T, std::enable_if_t<DataModel::IsFabricScoped<T0>::value, bool> = true>
     void SetFabricIndex(FabricIndex fabricIndex)
     {
@@ -189,38 +234,6 @@
     };
 
     Iterator begin() const { return Iterator(mReader, mFabricIndex); }
-
-    /*
-     * Compute the size of the list. This can fail if the TLV is malformed. If
-     * this succeeds, that does not guarantee that the individual items can be
-     * successfully decoded; consumers should check Iterator::GetStatus() when
-     * actually decoding them. If there is no list then the size is considered
-     * to be zero.
-     */
-    CHIP_ERROR ComputeSize(size_t * size) const
-    {
-        if (mReader.GetContainerType() == TLV::kTLVType_NotSpecified)
-        {
-            *size = 0;
-            return CHIP_NO_ERROR;
-        }
-
-        return mReader.CountRemainingInContainer(size);
-    }
-
-    CHIP_ERROR Decode(TLV::TLVReader & reader)
-    {
-        VerifyOrReturnError(reader.GetType() == TLV::kTLVType_Array, CHIP_ERROR_SCHEMA_MISMATCH);
-        TLV::TLVType type;
-        ReturnErrorOnFailure(reader.EnterContainer(type));
-        SetReader(reader);
-        ReturnErrorOnFailure(reader.ExitContainer(type));
-        return CHIP_NO_ERROR;
-    }
-
-private:
-    TLV::TLVReader mReader;
-    chip::Optional<FabricIndex> mFabricIndex;
 };
 
 } // namespace DataModel