gem5-dev@gem5.org

The gem5 Developer List

View all threads

[L] Change in gem5/gem5[develop]: base: Provide stl_helpers::operator<< for more types

BB
Bobby Bruce (Gerrit)
Mon, Jul 10, 2023 11:00 PM

Bobby Bruce has submitted this change. (
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
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/67666
Reviewed-by: Daniel Carvalho odanrc@yahoo.com.br
Tested-by: kokoro noreply+kokoro@google.com
Maintainer: Bobby Bruce bbruce@ucdavis.edu

M src/base/stl_helpers.hh
M src/base/stl_helpers/SConscript
A src/base/stl_helpers/ostream_helpers.hh
A src/base/stl_helpers/ostream_helpers.test.cc
4 files changed, 263 insertions(+), 53 deletions(-)

Approvals:
Bobby Bruce: Looks good to me, approved
kokoro: Regressions pass
Daniel Carvalho: Looks good to me, approved

diff --git a/src/base/stl_helpers.hh b/src/base/stl_helpers.hh
index 1d19f56..b70eea9 100644
--- a/src/base/stl_helpers.hh
+++ b/src/base/stl_helpers.hh
@@ -26,59 +26,10 @@

  • OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */

-#ifndef BASE_STL_HELPERS_HH
-#define BASE_STL_HELPERS_HH
+#ifndef BASE_STL_HELPERS_HH
+#define BASE_STL_HELPERS_HH

-#include <algorithm>
-#include <iostream>
-#include <numeric>
-#include <type_traits>
-#include <vector>

-#include "base/compiler.hh"
#include "base/stl_helpers/hash_helpers.hh"
+#include "base/stl_helpers/ostream_helpers.hh"

-namespace gem5
-{

-namespace stl_helpers
-{

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

-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
  • */

-template <typename T>
-std::enable_if_t<IsHelpedContainerV<T>, std::ostream &>
-operator<<(std::ostream& out, const T &t)
-{

  • 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;
    -}

-} // namespace stl_helpers
-} // namespace gem5

-#endif // BASE_STL_HELPERS_HH
+#endif // BASE_STL_HELPERS_HH
diff --git a/src/base/stl_helpers/SConscript
b/src/base/stl_helpers/SConscript
index 1143dc2..7328cf0 100644
--- a/src/base/stl_helpers/SConscript
+++ b/src/base/stl_helpers/SConscript
@@ -26,3 +26,4 @@
Import('*')

GTest('hash_helpers.test', 'hash_helpers.test.cc')
+GTest('ostream_helpers.test', 'ostream_helpers.test.cc')
diff --git a/src/base/stl_helpers/ostream_helpers.hh
b/src/base/stl_helpers/ostream_helpers.hh
new file mode 100644
index 0000000..a1c92e1
--- /dev/null
+++ b/src/base/stl_helpers/ostream_helpers.hh
@@ -0,0 +1,192 @@
+/*

    • Copyright (c) 2023 Arteris, Inc. and its applicable licensors and
    • affiliates.
    • All rights reserved.
    • Redistribution and use in source and binary forms, with or without
    • modification, are permitted provided that the following conditions are
    • met: redistributions of source code must retain the above copyright
    • notice, this list of conditions and the following disclaimer;
    • redistributions in binary form must reproduce the above copyright
    • notice, this list of conditions and the following disclaimer in the
    • documentation and/or other materials provided with the distribution;
    • neither the name of the copyright holders nor the names of its
    • contributors may be used to endorse or promote products derived from
    • this software without specific prior written permission.
    • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
      IS"
    • AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
      THE
    • IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      PURPOSE
    • ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    • LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    • CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    • SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    • INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    • CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    • ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
      THE
    • POSSIBILITY OF SUCH DAMAGE.
  • */

+#ifndef BASE_STL_HELPERS_OSTREAM_HELPERS_HH
+#define BASE_STL_HELPERS_OSTREAM_HELPERS_HH
+
+#include <iostream>
+#include <memory>
+#include <tuple>
+#include <utility>
+
+#include "base/type_traits.hh"
+#include "magic_enum/magic_enum.hh"
+
+namespace gem5::stl_helpers
+{
+
+namespace opExtract_impl
+{
+
+/*

    • 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::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)
+{

  • 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::enable_if_t<is_iterable_v<T>, std::ostream&>
+opExtractPrimDisp(std::ostream& os, const T& v)
+{

  • os << "[ ";
  • for (auto& e: v) {
  •    opExtractSecDisp(os, e) << ", ";
    
  • }
  • return os << ']';
    +}

+template <typename T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, const std::optional<T>& o)
+{

  • if (o) {
  •    return opExtractSecDisp(os, *o);
    
  • } else {
  •    return os << '-';
    
  • }
    +}

+template <typename T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, T* p);
+
+template <typename T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, const std::shared_ptr<T>& p)
+{

  • return opExtractPrimDisp(os, p.get());
    +}

+template <typename T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, const std::unique_ptr<T>& p)
+{

  • return opExtractPrimDisp(os, p.get());
    +}

+template <typename, typename = void>
+constexpr bool isOpExtractNativelySupported = false;
+
+template <typename T>
+constexpr bool isOpExtractNativelySupported<T,

  • std::void_t<decltype(
  •    std::declval<std::ostream&>() << std::declval<T>())>> = true;
    

+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>
+constexpr bool needsDispatch =

  • isOpExtractHelped<T> && !isOpExtractNativelySupported<T>;

+template <typename T>
+std::ostream&
+opExtractPrimDisp(std::ostream& os, T* p)
+{

  • if (!p) {
  •    return os << "nullptr";
    
  • }
  • if constexpr (isOpExtractHelped<T> || isOpExtractNativelySupported<T>)
    {
  •    os << '(' << p << ": ";
    
  •    opExtractSecDisp(os, *p);
    
  •    return os << ')';
    
  • } else {
  •    return os << p;
    
  • }
    +}

+template<typename T>
+std::ostream&
+opExtractSecDisp(std::ostream& os, const T& v)
+{

  • if constexpr (needsDispatch<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::needsDispatch<T>, std::ostream&>
+operator<<(std::ostream& os, const T& v)
+{

  • return opExtract_impl::opExtractPrimDisp(os, v);
    +}

+} // namespace gem5::stl_helpers
+
+#endif // BASE_STL_HELPERS_OSTREAM_HELPERS_HH
diff --git a/src/base/stl_helpers/ostream_helpers.test.cc
b/src/base/stl_helpers/ostream_helpers.test.cc
new file mode 100644
index 0000000..19a1ece
--- /dev/null
+++ b/src/base/stl_helpers/ostream_helpers.test.cc
@@ -0,0 +1,66 @@
+/*

    • Copyright (c) 2023 Arteris, Inc. and its applicable licensors and
    • affiliates.  All rights reserved.
    • Redistribution and use in source and binary forms, with or without
    • modification, are permitted provided that the following conditions are
      met:
    • redistributions of source code must retain the above copyright notice,
      this
    • list of conditions and the following disclaimer; redistributions in
      binary
    • form must reproduce the above copyright notice, this list of conditions
      and
    • the following disclaimer in the documentation and/or other materials
    • provided with the distribution; neither the name of the copyright
      holders
    • nor the names of its contributors may be used to endorse or promote
      products
    • derived from this software without specific prior written permission.
    • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
      IS"
    • AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
      THE
    • IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      PURPOSE
    • ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    • LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    • CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    • SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    • INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    • CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    • ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
      THE
    • POSSIBILITY OF SUCH DAMAGE.
  • */

+#include <gtest/gtest.h>
+
+#include <map>
+#include <sstream>
+#include <string_view>
+#include <vector>
+
+#include "base/stl_helpers/ostream_helpers.hh"
+
+using gem5::stl_helpers::operator<<;
+
+TEST(OstreamHelpers, pair) {

  • auto p = std::make_pair(1, 2);
  • std::ostringstream os;
  • os << p;
  • EXPECT_EQ(os.str(), "(1, 2)");
    +}

+TEST(OstreamHelpers, tuple) {

  • auto t = std::make_tuple(true,
  •    std::make_pair("Hello", std::string_view("World")), '!');
    
  • std::ostringstream os;
  • os << t;
  • EXPECT_EQ(os.str(), "(1, (Hello, World), !)");
    +}

+TEST(OstreamHelpers, vector) {

  • auto v = std::vector<const char*>{"abc", "defg", "hijklm", "\n"};
  • std::ostringstream os;
  • os << v;
  • EXPECT_EQ(os.str(), "[ abc, defg, hijklm, \n, ]");
    +}

+TEST(OstreamHelpers, map) {

  • auto m = std::map<char, int>{{'a', 0}, {'b', 1}, {'c', 2}, {'d', 3}};
  • std::ostringstream os;
  • os << m;
  • EXPECT_EQ(os.str(), "[ (a, 0), (b, 1), (c, 2), (d, 3), ]");
    +}

--
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?usp=email

Gerrit-MessageType: merged
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I1609dd6e85e25764f393458d736ec228e025da32
Gerrit-Change-Number: 67666
Gerrit-PatchSet: 16
Gerrit-Owner: Gabriel B. gabriel.busnot@arteris.com
Gerrit-Reviewer: Bobby Bruce bbruce@ucdavis.edu
Gerrit-Reviewer: Daniel Carvalho odanrc@yahoo.com.br
Gerrit-Reviewer: kokoro noreply+kokoro@google.com
Gerrit-CC: kokoro noreply+kokoro@google.com

Bobby Bruce has submitted this change. ( 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 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/67666 Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br> Tested-by: kokoro <noreply+kokoro@google.com> Maintainer: Bobby Bruce <bbruce@ucdavis.edu> --- M src/base/stl_helpers.hh M src/base/stl_helpers/SConscript A src/base/stl_helpers/ostream_helpers.hh A src/base/stl_helpers/ostream_helpers.test.cc 4 files changed, 263 insertions(+), 53 deletions(-) Approvals: Bobby Bruce: Looks good to me, approved kokoro: Regressions pass Daniel Carvalho: Looks good to me, approved diff --git a/src/base/stl_helpers.hh b/src/base/stl_helpers.hh index 1d19f56..b70eea9 100644 --- a/src/base/stl_helpers.hh +++ b/src/base/stl_helpers.hh @@ -26,59 +26,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __BASE_STL_HELPERS_HH__ -#define __BASE_STL_HELPERS_HH__ +#ifndef BASE_STL_HELPERS_HH +#define BASE_STL_HELPERS_HH -#include <algorithm> -#include <iostream> -#include <numeric> -#include <type_traits> -#include <vector> - -#include "base/compiler.hh" #include "base/stl_helpers/hash_helpers.hh" +#include "base/stl_helpers/ostream_helpers.hh" -namespace gem5 -{ - -namespace stl_helpers -{ - -template <typename T, typename Enabled=void> -struct IsHelpedContainer : public std::false_type {}; - -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 - */ - -template <typename T> -std::enable_if_t<IsHelpedContainerV<T>, std::ostream &> -operator<<(std::ostream& out, const T &t) -{ - 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; -} - -} // namespace stl_helpers -} // namespace gem5 - -#endif // __BASE_STL_HELPERS_HH__ +#endif // BASE_STL_HELPERS_HH diff --git a/src/base/stl_helpers/SConscript b/src/base/stl_helpers/SConscript index 1143dc2..7328cf0 100644 --- a/src/base/stl_helpers/SConscript +++ b/src/base/stl_helpers/SConscript @@ -26,3 +26,4 @@ Import('*') GTest('hash_helpers.test', 'hash_helpers.test.cc') +GTest('ostream_helpers.test', 'ostream_helpers.test.cc') diff --git a/src/base/stl_helpers/ostream_helpers.hh b/src/base/stl_helpers/ostream_helpers.hh new file mode 100644 index 0000000..a1c92e1 --- /dev/null +++ b/src/base/stl_helpers/ostream_helpers.hh @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2023 Arteris, Inc. and its applicable licensors and + * affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BASE_STL_HELPERS_OSTREAM_HELPERS_HH +#define BASE_STL_HELPERS_OSTREAM_HELPERS_HH + +#include <iostream> +#include <memory> +#include <tuple> +#include <utility> + +#include "base/type_traits.hh" +#include "magic_enum/magic_enum.hh" + +namespace gem5::stl_helpers +{ + +namespace opExtract_impl +{ + +/* + * 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::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) +{ + 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::enable_if_t<is_iterable_v<T>, std::ostream&> +opExtractPrimDisp(std::ostream& os, const T& v) +{ + os << "[ "; + for (auto& e: v) { + opExtractSecDisp(os, e) << ", "; + } + return os << ']'; +} + +template <typename T> +std::ostream& +opExtractPrimDisp(std::ostream& os, const std::optional<T>& o) +{ + if (o) { + return opExtractSecDisp(os, *o); + } else { + return os << '-'; + } +} + +template <typename T> +std::ostream& +opExtractPrimDisp(std::ostream& os, T* p); + +template <typename T> +std::ostream& +opExtractPrimDisp(std::ostream& os, const std::shared_ptr<T>& p) +{ + return opExtractPrimDisp(os, p.get()); +} + +template <typename T> +std::ostream& +opExtractPrimDisp(std::ostream& os, const std::unique_ptr<T>& p) +{ + return opExtractPrimDisp(os, p.get()); +} + +template <typename, typename = void> +constexpr bool isOpExtractNativelySupported = false; + +template <typename T> +constexpr bool isOpExtractNativelySupported<T, + std::void_t<decltype( + std::declval<std::ostream&>() << std::declval<T>())>> = true; + +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> +constexpr bool needsDispatch = + isOpExtractHelped<T> && !isOpExtractNativelySupported<T>; + +template <typename T> +std::ostream& +opExtractPrimDisp(std::ostream& os, T* p) +{ + if (!p) { + return os << "nullptr"; + } + if constexpr (isOpExtractHelped<T> || isOpExtractNativelySupported<T>) { + os << '(' << p << ": "; + opExtractSecDisp(os, *p); + return os << ')'; + } else { + return os << p; + } +} + +template<typename T> +std::ostream& +opExtractSecDisp(std::ostream& os, const T& v) +{ + if constexpr (needsDispatch<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::needsDispatch<T>, std::ostream&> +operator<<(std::ostream& os, const T& v) +{ + return opExtract_impl::opExtractPrimDisp(os, v); +} + +} // namespace gem5::stl_helpers + +#endif // BASE_STL_HELPERS_OSTREAM_HELPERS_HH diff --git a/src/base/stl_helpers/ostream_helpers.test.cc b/src/base/stl_helpers/ostream_helpers.test.cc new file mode 100644 index 0000000..19a1ece --- /dev/null +++ b/src/base/stl_helpers/ostream_helpers.test.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Arteris, Inc. and its applicable licensors and + * affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer; redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials + * provided with the distribution; neither the name of the copyright holders + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <gtest/gtest.h> + +#include <map> +#include <sstream> +#include <string_view> +#include <vector> + +#include "base/stl_helpers/ostream_helpers.hh" + +using gem5::stl_helpers::operator<<; + +TEST(OstreamHelpers, pair) { + auto p = std::make_pair(1, 2); + std::ostringstream os; + os << p; + EXPECT_EQ(os.str(), "(1, 2)"); +} + +TEST(OstreamHelpers, tuple) { + auto t = std::make_tuple(true, + std::make_pair("Hello", std::string_view("World")), '!'); + std::ostringstream os; + os << t; + EXPECT_EQ(os.str(), "(1, (Hello, World), !)"); +} + +TEST(OstreamHelpers, vector) { + auto v = std::vector<const char*>{"abc", "defg", "hijklm", "\n"}; + std::ostringstream os; + os << v; + EXPECT_EQ(os.str(), "[ abc, defg, hijklm, \n, ]"); +} + +TEST(OstreamHelpers, map) { + auto m = std::map<char, int>{{'a', 0}, {'b', 1}, {'c', 2}, {'d', 3}}; + std::ostringstream os; + os << m; + EXPECT_EQ(os.str(), "[ (a, 0), (b, 1), (c, 2), (d, 3), ]"); +} -- 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?usp=email Gerrit-MessageType: merged Gerrit-Project: public/gem5 Gerrit-Branch: develop Gerrit-Change-Id: I1609dd6e85e25764f393458d736ec228e025da32 Gerrit-Change-Number: 67666 Gerrit-PatchSet: 16 Gerrit-Owner: Gabriel B. <gabriel.busnot@arteris.com> Gerrit-Reviewer: Bobby Bruce <bbruce@ucdavis.edu> Gerrit-Reviewer: Daniel Carvalho <odanrc@yahoo.com.br> Gerrit-Reviewer: kokoro <noreply+kokoro@google.com> Gerrit-CC: kokoro <noreply+kokoro@google.com>