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