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