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