Gabriel B. has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/67666?usp=email )

Change subject: base: Provide stl_helpers::operator<< for more types
......................................................................

base: Provide stl_helpers::operator<< for more types

This operator can be safely brought in scope when needed with "using
stl_helpers::operator<<".

In order to provide a specialization for operator<< with
stl_helpers-enabled types without loosing the hability to use it with
other types, a dual-dispatch mechanism is used. The only entry point
in the system is through a primary dispatch function that won't
resolve for non-helped types. Then, recursive calls go through the
secondary dispatch interface that sort between helped and non-helped
types. Helped typed will enter the system back through the primary
dispatch interface while other types will look for operator<< through
regular lookup, especially ADL.

Change-Id: I1609dd6e85e25764f393458d736ec228e025da32
---
M src/base/stl_helpers.hh
1 file changed, 104 insertions(+), 28 deletions(-)



diff --git a/src/base/stl_helpers.hh b/src/base/stl_helpers.hh
index f14f109..c26270a 100644
--- a/src/base/stl_helpers.hh
+++ b/src/base/stl_helpers.hh
@@ -38,6 +38,7 @@
 #include <vector>

 #include "base/compiler.hh"
+#include "magic_enum/magic_enum.hh"

 namespace gem5
 {
@@ -45,38 +46,91 @@
 namespace stl_helpers
 {

-template <typename T, typename Enabled=void>
-struct IsHelpedContainer : public std::false_type {};
+namespace opExtract_impl {

-template <typename ...Types>
-struct IsHelpedContainer<std::vector<Types...>> : public std::true_type {};
-
-template <typename ...Types>
-constexpr bool IsHelpedContainerV = IsHelpedContainer<Types...>::value;
-
-/**
- * Write out all elements in an stl container as a space separated
- * list enclosed in square brackets
- *
- * @ingroup api_base_utils
+/*
+ * In order to provide a specialization for operator<< with stl_helpers-enabled
+ * types
+ * without loosing the hability to use it with other types, a dual-dispatch
+ * mechanism is used. The only entry point in the system is through a primary + * dispatch function that won't resolve for non-helped types. Then, recursive + * calls go through the secondary dispatch interface that sort between helped + * and non-helped types. Helped typed will enter the system back through the
+ * primary dispatch interface while other types will look for operator<<
+ * through regular lookup, especially ADL.
  */

-template <typename T>
-std::enable_if_t<IsHelpedContainerV<T>, std::ostream &>
-operator<<(std::ostream& out, const T &t)
+template<typename T>
+std::ostream&
+opExtractSecDisp(std::ostream& os, const T& v);
+
+template <typename E>
+std::enable_if_t<std::is_enum_v<E>,
+std::ostream&>
+opExtractPrimDisp(std::ostream& os, const E& e)
 {
-    out << "[ ";
-    bool first = true;
-    auto printer = [&first, &out](const auto &elem) {
-        if (first)
-            out << elem;
-        else
-            out << " " << elem;
-    };
-    std::for_each(t.begin(), t.end(), printer);
-    out << " ]";
-    out << std::flush;
-    return out;
+    return os << magic_enum::enum_name(e);
+}
+
+template <typename... T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, const std::tuple<T...>& p)
+{
+    std::apply([&](auto&&... e) {
+        std::size_t n{0};
+        os << '(';
+ ((opExtractSecDisp(os, e) << (++n != sizeof...(T) ? ", " : "")), ...);
+        os << ')';
+    }, p);
+    return os;
+}
+
+template <typename T, typename U>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, const std::pair<T, U>& p)
+{
+    return opExtractPrimDisp(os, std::tie(p.first, p.second));
+}
+
+template <typename... T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, const std::vector<T...>& v)
+{
+    os << "[ ";
+    for (auto& e: v) {
+        os << e << ' ';
+    }
+    return os << ']';
+}
+
+template <typename, typename = void>
+constexpr bool isOpExtractHelped = false;
+
+template <typename T>
+constexpr bool isOpExtractHelped<T,
+    std::void_t<decltype(
+        opExtractPrimDisp(std::declval<std::ostream&>(),
+                          std::declval<T>()))>> = true;
+
+template<typename T>
+std::ostream&
+opExtractSecDisp(std::ostream& os, const T& v)
+{
+    if constexpr (isOpExtractHelped<T>) {
+        return opExtractPrimDisp(os, v);
+    } else {
+        return os << v;
+    }
+}
+
+} // namespace opExtract_impl
+
+// Add "using stl_helpers::operator<<" in the scope where you want to use it.
+template<typename T>
+std::enable_if_t<opExtract_impl::isOpExtractHelped<T>, std::ostream&>
+operator<<(std::ostream& os, const T& v)
+{
+    return opExtract_impl::opExtractPrimDisp(os, v);
 }

 namespace hash_impl {

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/67666?usp=email To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I1609dd6e85e25764f393458d736ec228e025da32
Gerrit-Change-Number: 67666
Gerrit-PatchSet: 1
Gerrit-Owner: Gabriel B. <gabriel.bus...@arteris.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org

Reply via email to