• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_SRC_CORE_UTIL_DUMP_ARGS_H
16 #define GRPC_SRC_CORE_UTIL_DUMP_ARGS_H
17 
18 #include <ostream>
19 #include <vector>
20 
21 #include "absl/functional/any_invocable.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 #include "absl/strings/string_view.h"
25 
26 namespace grpc_core {
27 namespace dump_args_detail {
28 
29 // Helper function... just ignore the initializer list passed into it.
30 // Allows doing 'statements' via parameter pack expansion in C++11 - given
31 // template <typename... Ts>:
32 //  do_these_things({foo<Ts>()...});
33 // will execute foo<T>() for each T in Ts.
34 template <typename T>
do_these_things(std::initializer_list<T>)35 void do_these_things(std::initializer_list<T>) {}
36 
37 class DumpArgs {
38  public:
39   template <typename... Args>
DumpArgs(const char * arg_string,const Args &...args)40   explicit DumpArgs(const char* arg_string, const Args&... args)
41       : arg_string_(arg_string) {
42     do_these_things({AddDumper(&args)...});
43   }
44 
45   template <typename Sink>
AbslStringify(Sink & sink,const DumpArgs & dumper)46   friend void AbslStringify(Sink& sink, const DumpArgs& dumper) {
47     CustomSinkImpl<Sink> custom_sink(sink);
48     dumper.Stringify(custom_sink);
49   }
50 
51   friend std::ostream& operator<<(std::ostream& out, const DumpArgs& dumper) {
52     return out << absl::StrCat(dumper);
53   }
54 
55  private:
56   class CustomSink {
57    public:
58     virtual void Append(absl::string_view x) = 0;
59 
60    protected:
61     ~CustomSink() = default;
62   };
63 
64   template <typename Sink>
65   class CustomSinkImpl final : public CustomSink {
66    public:
CustomSinkImpl(Sink & sink)67     explicit CustomSinkImpl(Sink& sink) : sink_(sink) {}
Append(absl::string_view x)68     void Append(absl::string_view x) override { sink_.Append(x); }
69 
70    private:
71     Sink& sink_;
72   };
73 
74   template <typename T>
AddDumper(T * p)75   int AddDumper(T* p) {
76     arg_dumpers_.push_back(
77         [p](CustomSink& os) { os.Append(absl::StrCat(*p)); });
78     return 0;
79   }
80 
AddDumper(void const * const * p)81   int AddDumper(void const* const* p) {
82     arg_dumpers_.push_back(
83         [p](CustomSink& os) { os.Append(absl::StrFormat("%p", *p)); });
84     return 0;
85   }
86 
87   template <typename T>
AddDumper(T const * const * p)88   int AddDumper(T const* const* p) {
89     return AddDumper(reinterpret_cast<void const* const*>(p));
90   }
91 
92   template <typename T>
AddDumper(T * const * p)93   int AddDumper(T* const* p) {
94     return AddDumper(const_cast<T const* const*>(p));
95   }
96 
97   template <typename T>
AddDumper(T const ** p)98   int AddDumper(T const** p) {
99     return AddDumper(const_cast<T const* const*>(p));
100   }
101 
102   void Stringify(CustomSink& sink) const;
103 
104   const char* arg_string_;
105   std::vector<absl::AnyInvocable<void(CustomSink&) const>> arg_dumpers_;
106 };
107 
108 }  // namespace dump_args_detail
109 }  // namespace grpc_core
110 
111 // Helper to print a list of variables and their values.
112 // Each type must be streamable to std::ostream.
113 // Usage:
114 //   int a = 1;
115 //   int b = 2;
116 //   LOG(INFO) << GRPC_DUMP_ARGS(a, b)
117 // Output:
118 //   a = 1, b = 2
119 #define GRPC_DUMP_ARGS(...) \
120   grpc_core::dump_args_detail::DumpArgs(#__VA_ARGS__, __VA_ARGS__)
121 
122 #endif  // GRPC_SRC_CORE_UTIL_DUMP_ARGS_H
123