gem5 v24.0.0.0
Loading...
Searching...
No Matches
ostream_helpers.hh
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 Arteris, Inc. and its applicable licensors and
3 * affiliates.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#ifndef BASE_STL_HELPERS_OSTREAM_HELPERS_HH
31#define BASE_STL_HELPERS_OSTREAM_HELPERS_HH
32
33#include <iostream>
34#include <memory>
35#include <tuple>
36#include <utility>
37
38#include "base/type_traits.hh"
39#include "magic_enum/magic_enum.hh"
40
41namespace gem5::stl_helpers
42{
43
44/*
45 * Wrap any object in a Printer object to force using a opExtract_impl printing
46 * function. This is not required for types that do not already enable
47 * operator<< in another namespace. However, to enable the special printing
48 * function for, e.g., raw pointers, those must be wrapped in a Printer.
49 */
50template<typename T>
51struct Printer
52{
53 Printer(const T& value): value{value} {}
54 const T& value;
55};
56
57namespace opExtract_impl
58{
59
60/*
61 * In order to provide a specialization for operator<< with stl_helpers-enabled
62 * types
63 * without loosing the hability to use it with other types, a dual-dispatch
64 * mechanism is used. The only entry point in the system is through a primary
65 * dispatch function that won't resolve for non-helped types. Then, recursive
66 * calls go through the secondary dispatch interface that sort between helped
67 * and non-helped types. Helped types will enter the system back through the
68 * primary dispatch interface while other types will look for operator<<
69 * through regular lookup, especially ADL.
70 */
71
72template<typename T>
73std::ostream&
74opExtractSecDisp(std::ostream& os, const T& v);
75
76template <typename E>
77std::enable_if_t<std::is_enum_v<E>,
78std::ostream&>
79opExtractPrimDisp(std::ostream& os, const E& e)
80{
81 return os << magic_enum::enum_name(e);
82}
83
84template <typename... T>
85std::ostream&
86opExtractPrimDisp(std::ostream& os, const std::tuple<T...>& p)
87{
88 std::apply([&](auto&&... e) {
89 std::size_t n{0};
90 os << '(';
91 ((opExtractSecDisp(os, e) << (++n != sizeof...(T) ? ", " : "")), ...);
92 os << ')';
93 }, p);
94 return os;
95}
96
97template <typename T, typename U>
98std::ostream&
99opExtractPrimDisp(std::ostream& os, const std::pair<T, U>& p)
100{
101 return opExtractPrimDisp(os, std::tie(p.first, p.second));
102}
103
104template <typename T>
105std::enable_if_t<is_iterable_v<T>, std::ostream&>
106opExtractPrimDisp(std::ostream& os, const T& v)
107{
108 os << "[ ";
109 for (auto& e: v) {
110 opExtractSecDisp(os, e) << ", ";
111 }
112 return os << ']';
113}
114
115template <typename T>
116std::ostream&
117opExtractPrimDisp(std::ostream& os, const std::optional<T>& o)
118{
119 if (o) {
120 return opExtractSecDisp(os, *o);
121 } else {
122 return os << "(-)";
123 }
124}
125
126template <typename T>
127std::ostream&
128opExtractPrimDisp(std::ostream& os, T* p);
129
130template <typename T>
131std::ostream&
132opExtractPrimDisp(std::ostream& os, const std::shared_ptr<T>& p)
133{
134 return opExtractPrimDisp(os, p.get());
135}
136
137template <typename T>
138std::ostream&
139opExtractPrimDisp(std::ostream& os, const std::unique_ptr<T>& p)
140{
141 return opExtractPrimDisp(os, p.get());
142}
143
144template <typename T>
145std::ostream&
146opExtractPrimDisp(std::ostream& os, const Printer<T>& p);
147
148template <typename, typename = void>
149constexpr bool isOpExtractNativelySupported = false;
150
151template <typename T>
152constexpr bool isOpExtractNativelySupported<T,
153 std::void_t<decltype(
154 std::declval<std::ostream&>() << std::declval<T>())>> = true;
155
156template <typename, typename = void>
157constexpr bool isOpExtractHelped = false;
158
159template <typename T>
160constexpr bool isOpExtractHelped<T,
161 std::void_t<decltype(
162 opExtractPrimDisp(std::declval<std::ostream&>(),
163 std::declval<T>()))>>
164 = true;
165
166template <typename T>
167constexpr bool needsDispatch =
169
170template <typename T>
171std::ostream&
172opExtractPrimDisp(std::ostream& os, T* p)
173{
174 if (!p) {
175 return os << "nullptr";
176 }
178 os << '(' << p << ": ";
180 return os << ')';
181 } else {
182 return os << p;
183 }
184}
185
186template <typename T>
187std::ostream&
188opExtractPrimDisp(std::ostream& os, const Printer<T>& p)
189{
190 if constexpr (isOpExtractHelped<T>) {
191 return opExtractPrimDisp(os, p.value);
192 } else {
193 return os << p.value;
194 }
195}
196
197
198template<typename T>
199std::ostream&
200opExtractSecDisp(std::ostream& os, const T& v)
201{
202 if constexpr (needsDispatch<T>) {
203 return opExtractPrimDisp(os, v);
204 } else {
205 return os << v;
206 }
207}
208
209} // namespace opExtract_impl
210
211// use the Printer wrapper or add "using stl_helpers::operator<<" in the scope
212// where you want to use that operator<<.
213template<typename T>
214std::enable_if_t<opExtract_impl::needsDispatch<T>, std::ostream&>
215operator<<(std::ostream& os, const T& v)
216{
218}
219
220} // namespace gem5::stl_helpers
221
222#endif // BASE_STL_HELPERS_OSTREAM_HELPERS_HH
STL pair class.
Definition stl.hh:58
Bitfield< 28 > v
Definition misc_types.hh:54
Bitfield< 31 > n
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 0 > p
Bitfield< 31, 0 > E
Definition int.hh:56
Bitfield< 17 > os
Definition misc.hh:838
std::ostream & opExtractSecDisp(std::ostream &os, const T &v)
std::enable_if_t< std::is_enum_v< E >, std::ostream & > opExtractPrimDisp(std::ostream &os, const E &e)
std::enable_if_t< opExtract_impl::needsDispatch< T >, std::ostream & > operator<<(std::ostream &os, const T &v)

Generated on Tue Jun 18 2024 16:24:01 for gem5 by doxygen 1.11.0