Fixup gold-plugin after r227576.
[oota-llvm.git] / tools / llvm-pdbdump / COMExtras.h
1 //===- COMExtras.h - Helper files for COM operations -------------*- C++-*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef LLVM_TOOLS_LLVM_PDBDUMP_COMEXTRAS_H
11 #define LLVM_TOOLS_LLVM_PDBDUMP_COMEXTRAS_H
12
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/Support/ConvertUTF.h"
16
17 #include <tuple>
18
19 namespace llvm {
20
21 template <typename F> struct function_traits;
22
23 #if LLVM_HAS_VARIADIC_TEMPLATES
24 template <typename R, typename... Args>
25 struct function_traits<R (*)(Args...)> : public function_traits<R(Args...)> {};
26
27 template <typename C, typename R, typename... Args>
28 struct function_traits<R (__stdcall C::*)(Args...)> {
29   using args_tuple = std::tuple<Args...>;
30 };
31 #else
32
33 // For the sake of COM, we only need a 3 argument version and a 5 argument
34 // version. We could provide 1, 2, 4, and other length of argument lists if
35 // this were intended to be more generic.  Alternatively, this will "just work"
36 // if VS2012 support is dropped and we can use the variadic template case
37 // exclusively.
38 template <typename C, typename R, typename A1, typename A2, typename A3>
39 struct function_traits<R (__stdcall C::*)(A1, A2, A3)> {
40   typedef std::tuple<A1, A2, A3> args_tuple;
41 };
42
43 template <typename C, typename R, typename A1, typename A2, typename A3,
44           typename A4, typename A5>
45 struct function_traits<R (__stdcall C::*)(A1, A2, A3, A4, A5)> {
46   typedef std::tuple<A1, A2, A3, A4, A5> args_tuple;
47 };
48 #endif
49
50 template <class FuncTraits, std::size_t arg> struct function_arg {
51   // Writing function_arg as a separate class that accesses the tuple from
52   // function_traits is necessary due to what appears to be a bug in MSVC.
53   // If you write a nested class inside function_traits like this:
54   // template<std::size_t ArgIndex>
55   // struct Argument
56   // {
57   //   typedef typename
58   //     std::tuple_element<ArgIndex, std::tuple<Args...>>::type type;
59   // };
60   // MSVC encounters a parsing error.
61   typedef
62       typename std::tuple_element<arg, typename FuncTraits::args_tuple>::type
63           type;
64 };
65
66 template <class T> struct remove_double_pointer {};
67 template <class T> struct remove_double_pointer<T **> { typedef T type; };
68
69 namespace sys {
70 namespace windows {
71
72 /// A helper class for allowing the use of COM enumerators in range-based
73 /// for loops.
74 ///
75 /// A common idiom in the COM world is to have an enumerator interface, say
76 /// IMyEnumerator.  It's responsible for enumerating over some child data type,
77 /// say IChildType.  You do the enumeration by calling IMyEnumerator::Next()
78 /// one of whose arguments will be an IChildType**.  Eventually Next() fails,
79 /// indicating that there are no more items.
80 ///
81 /// com_iterator represents a single point-in-time of this iteration.  It is
82 /// used by ComEnumerator to support iterating in this fashion via range-based
83 /// for loops and other common C++ paradigms.
84 template <class EnumeratorType, std::size_t ArgIndex> class com_iterator {
85   using FunctionTraits = function_traits<decltype(&EnumeratorType::Next)>;
86   typedef typename function_arg<FunctionTraits, ArgIndex>::type FuncArgType;
87   // FuncArgType is now something like ISomeCOMInterface **.  Remove both
88   // pointers, so we can make a CComPtr<T> out of it.
89   typedef typename remove_double_pointer<FuncArgType>::type EnumDataType;
90
91   CComPtr<EnumeratorType> EnumeratorObject;
92   CComPtr<EnumDataType> CurrentItem;
93
94 public:
95   typedef CComPtr<EnumDataType> value_type;
96   typedef std::ptrdiff_t difference_type;
97   typedef value_type *pointer_type;
98   typedef value_type &reference_type;
99   typedef std::forward_iterator_tag iterator_category;
100
101   explicit com_iterator(CComPtr<EnumeratorType> Enumerator,
102                         CComPtr<EnumDataType> Current)
103       : EnumeratorObject(Enumerator), CurrentItem(Current) {}
104   com_iterator() {}
105
106   com_iterator &operator++() {
107     // EnumeratorObject->Next() expects CurrentItem to be NULL.
108     CurrentItem.Release();
109     ULONG Count = 0;
110     HRESULT hr = EnumeratorObject->Next(1, &CurrentItem, &Count);
111     if (FAILED(hr) || Count == 0)
112       *this = com_iterator();
113
114     return *this;
115   }
116
117   value_type operator*() { return CurrentItem; }
118
119   bool operator==(const com_iterator &other) const {
120     return (EnumeratorObject == other.EnumeratorObject) &&
121            (CurrentItem == other.CurrentItem);
122   }
123
124   bool operator!=(const com_iterator &other) const { return !(*this == other); }
125
126   com_iterator &operator=(const com_iterator &other) {
127     EnumeratorObject = other.EnumeratorObject;
128     CurrentItem = other.CurrentItem;
129     return *this;
130   }
131 };
132
133 /// ComEnumerator implements the interfaced required for C++ to allow its use
134 /// in range-based for loops.  In particular, a begin() and end() method.
135 /// These methods simply construct and return an appropriate ComIterator
136 /// instance.
137 template <class EnumeratorType, std::size_t ArgIndex> class com_enumerator {
138   typedef function_traits<decltype(&EnumeratorType::Next)> FunctionTraits;
139   typedef typename function_arg<FunctionTraits, ArgIndex>::type FuncArgType;
140   typedef typename remove_double_pointer<FuncArgType>::type EnumDataType;
141
142   CComPtr<EnumeratorType> EnumeratorObject;
143
144 public:
145   com_enumerator(CComPtr<EnumeratorType> Enumerator)
146       : EnumeratorObject(Enumerator) {}
147
148   com_iterator<EnumeratorType, ArgIndex> begin() {
149     if (!EnumeratorObject)
150       return end();
151
152     EnumeratorObject->Reset();
153     ULONG Count = 0;
154     CComPtr<EnumDataType> FirstItem;
155     HRESULT hr = EnumeratorObject->Next(1, &FirstItem, &Count);
156     return (FAILED(hr) || Count == 0) ? end()
157                                       : com_iterator<EnumeratorType, ArgIndex>(
158                                             EnumeratorObject, FirstItem);
159   }
160
161   com_iterator<EnumeratorType, ArgIndex> end() {
162     return com_iterator<EnumeratorType, ArgIndex>();
163   }
164 };
165
166 /// A helper class for allowing the use of COM record enumerators in range-
167 /// based for loops.
168 ///
169 /// A record enumerator is almost the same as a regular enumerator, except
170 /// that it returns raw byte-data instead of interfaces to other COM objects.
171 /// As a result, the enumerator's Next() method has a slightly different
172 /// signature, and an iterator dereferences to an ArrayRef instead of a
173 /// CComPtr.
174 template <class EnumeratorType> class com_data_record_iterator {
175 public:
176   typedef llvm::ArrayRef<uint8_t> value_type;
177   typedef std::ptrdiff_t difference_type;
178   typedef value_type *pointer_type;
179   typedef value_type &reference_type;
180   typedef std::forward_iterator_tag iterator_category;
181
182   explicit com_data_record_iterator(CComPtr<EnumeratorType> enumerator)
183       : Enumerator(enumerator), CurrentRecord(0) {
184     // Make sure we start at the beginning.  If there are no records,
185     // immediately set ourselves equal to end().
186     if (enumerator)
187       enumerator->Reset();
188
189     if (!ReadNextRecord())
190       *this = com_data_record_iterator();
191   }
192   com_data_record_iterator() {}
193
194   com_data_record_iterator &operator++() {
195     ++CurrentRecord;
196     // If we can't read any more records, either because there are no more
197     // or because we encountered an error, we should compare equal to end.
198     if (!ReadNextRecord())
199       *this = com_data_record_iterator();
200     return *this;
201   }
202
203   value_type operator*() {
204     return llvm::ArrayRef<uint8_t>(RecordData.begin(), RecordData.end());
205   }
206
207   bool operator==(const com_data_record_iterator &other) const {
208     return (Enumerator == other.Enumerator) &&
209            (CurrentRecord == other.CurrentRecord);
210   }
211
212   bool operator!=(const com_data_record_iterator &other) const {
213     return !(*this == other);
214   }
215
216 private:
217   bool ReadNextRecord() {
218     RecordData.clear();
219     ULONG Count = 0;
220     DWORD RequiredBufferSize;
221     HRESULT hr = Enumerator->Next(1, 0, &RequiredBufferSize, nullptr, &Count);
222     if (hr == S_OK) {
223       RecordData.resize(RequiredBufferSize);
224       DWORD BytesRead = 0;
225       hr = Enumerator->Next(1, RequiredBufferSize, &BytesRead,
226                             RecordData.data(), &Count);
227     }
228     if (hr != S_OK)
229       RecordData.clear();
230     return (hr == S_OK);
231   }
232
233   CComPtr<EnumeratorType> Enumerator;
234   uint32_t CurrentRecord;
235   llvm::SmallVector<uint8_t, 32> RecordData;
236 };
237
238 /// Similar to ComEnumerator, com_data_record_enumerator implements the range
239 /// interface for ComDataRecordIterators.
240 template <class EnumeratorType> class com_data_record_enumerator {
241 public:
242   com_data_record_enumerator(CComPtr<EnumeratorType> enumerator)
243       : Enumerator(enumerator) {}
244
245   com_data_record_iterator<EnumeratorType> begin() {
246     return com_data_record_iterator<EnumeratorType>(Enumerator);
247   }
248
249   com_data_record_iterator<EnumeratorType> end() {
250     LONG NumElts = 0;
251     HRESULT hr = Enumerator->get_Count(&NumElts);
252     return (FAILED(hr)) ? com_data_record_iterator<EnumeratorType>(Enumerator)
253                         : com_data_record_iterator<EnumeratorType>();
254   }
255
256 private:
257   CComPtr<EnumeratorType> Enumerator;
258 };
259
260 /// com_enumerator is a simple helper function to allow the enumerator
261 /// class's type to be inferred automatically.
262 /// This allows you to write simply:
263 ///   for (auto item : com_enumerator(MyEnumerator)) {
264 ///   }
265 template <class EnumeratorType>
266 com_enumerator<EnumeratorType, 1>
267 make_com_enumerator(CComPtr<EnumeratorType> Enumerator) {
268   return com_enumerator<EnumeratorType, 1>(Enumerator);
269 }
270
271 /// com_data_record_enumerator is a simple helper function to allow the
272 /// enumerator class's type to be inferred automatically.
273 /// This allows you to write simply:
274 ///   for (auto item : com_data_record_enumerator(MyEnumerator)) {
275 ///   }
276 //=============================================================================
277 template <class EnumeratorType>
278 com_data_record_enumerator<EnumeratorType>
279 make_com_data_record_enumerator(CComPtr<EnumeratorType> Enumerator) {
280   return com_data_record_enumerator<EnumeratorType>(Enumerator);
281 }
282
283 inline bool BSTRToUTF8(BSTR String16, std::string &String8) {
284   UINT ByteLength = ::SysStringByteLen(String16);
285   char *Bytes = reinterpret_cast<char *>(String16);
286   String8.clear();
287   return llvm::convertUTF16ToUTF8String(ArrayRef<char>(Bytes, ByteLength),
288                                         String8);
289 }
290
291 } // namespace windows
292 } // namespace sys
293 } // namespace llvm
294
295 #endif