Merge pull request #2890 from sivarv/master
[platform/upstream/coreclr.git] / src / debug / di / rsenumerator.hpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
5 // 
6
7 //
8 // Implementation of CordbEnumerator, a templated COM enumeration pattern on Rs
9 // types
10 //*****************************************************************************
11
12 #include "rspriv.h"
13
14 // This CordbEnumerator is a templated enumerator from which COM enumerators for RS types can quickly be fashioned.
15 // It uses a private array to store the items it enumerates over so by default it does not reference any
16 // other RS type except the process it is associated with. The internal storage type does not need to match the
17 // the item type exposed publically so that you can easily create an enumeration that holds RsSmartPtr<CordbThread>
18 // but enumerates ICorDebugThread objects as an example. The enumerator has 4 templated parameters which must be
19 // defined:
20 //   ElemType: this is the item type used for storage internal to the enumerator. For most Rs objects you will want
21 //             to use an RsSmartPtr<T> type to ensure the enumerator holds references to the objects it is
22 //             containing. The enumerator does not do any explicit Add/Release, it just copies items.
23 //   ElemPublicType: this is the item type exposed publically via the Next enumeration method. Typically this is
24 //             an ICorDebugX interface type but it can be anything.
25 //   EnumInterfaceType: this is the COM interface that the instantiated template will implement. It is expected that
26 //             this interface type follows the standard ICorDebug COM enumerator pattern, that the interface inherits
27 //             ICorDebugEnum and defines a strongly typed Next, enumerating over the ElemPublicType.
28 //   GetPublicType: this is a function which converts from ElemType -> ElemPublicType. It is used to produce the
29 //             elements that Next actually enumerates from the internal data the enumerator stores. Two conversion
30 //             functions are already defined here for convenience: QueryInterfaceConvert and IdentityConvert. If
31 //             neither of those suits your needs then you can define your own.
32 //
33 // Note: As of right now (10/13/08) most of the ICorDebug enumerators are not implemented using this base class,
34 // however it might be good if we converged on this solution. There seems to be quite a bit of redundant and
35 // one-off enumeration code that could be eliminated.
36 // 
37
38 // A conversion function that converts from T to U by performing COM QueryInterface
39 template<typename T, typename U>
40 U * QueryInterfaceConvert(T obj)
41 {
42     U* pPublic;
43     obj->QueryInterface(__uuidof(U), (void**) &pPublic);
44     return pPublic;
45 }
46
47 // A conversion identity function that just returns its argument
48 template<typename T>
49 T IdentityConvert(T obj)
50 {
51     return obj;
52 }
53
54 // Constructor for an CordbEnumerator.
55 // Arguments:
56 //   pProcess - the CordbProcess with which to associate this enumerator
57 //   items - the set of items which should be enumerated
58 //   countItems - the number of items in the array pointed to by items
59 //
60 // Note that the items are copied into an internal array, and no reference is kept to the users array.
61 // Use RsSmartPtr types instead of Rs types directly to keep accurate ref counting for types which need it
62 template< typename ElemType, 
63           typename ElemPublicType,
64           typename EnumInterfaceType,
65           ElemPublicType (*GetPublicType)(ElemType)>
66 CordbEnumerator<ElemType,
67                 ElemPublicType,
68                 EnumInterfaceType,
69                 GetPublicType>::CordbEnumerator(CordbProcess *pProcess,
70                                                 ElemType *items,
71                                                 DWORD countItems) :
72 CordbBase(pProcess, 0, enumCordbEnumerator),
73 m_countItems(countItems),
74 m_nextIndex(0)
75 {
76     m_items = new ElemType[countItems];
77     for(UINT i = 0; i < countItems; i++)
78     {
79         m_items[i] = items[i];
80     }
81 }
82
83 // Constructor for an CordbEnumerator.
84 // Arguments:
85 //   pProcess - the CordbProcess with which to associate this enumerator
86 //   items - the address of an array of items which should be enumerated
87 //   countItems - the number of items in the array pointed to by items
88 //
89 // Note that the items array is simply taken over, setting *items to NULL.
90 // Use RsSmartPtr types instead of Rs types directly to keep accurate ref counting for types which need it
91 template< typename ElemType, 
92           typename ElemPublicType,
93           typename EnumInterfaceType,
94           ElemPublicType (*GetPublicType)(ElemType)>
95 CordbEnumerator<ElemType,
96                 ElemPublicType,
97                 EnumInterfaceType,
98                 GetPublicType>::CordbEnumerator(CordbProcess *pProcess,
99                                                 ElemType **items,
100                                                 DWORD countItems) :
101 CordbBase(pProcess, 0, enumCordbEnumerator),
102 m_nextIndex(0),
103 m_countItems(countItems)
104 {
105     _ASSERTE(items != NULL);
106     m_items = *items;
107     *items = NULL;
108 }
109
110 // Destructor
111 template< typename ElemType, 
112           typename ElemPublicType,
113           typename EnumInterfaceType,
114           ElemPublicType (*GetPublicType)(ElemType)>
115 CordbEnumerator<ElemType,
116                 ElemPublicType,
117                 EnumInterfaceType,
118                 GetPublicType>::~CordbEnumerator()
119 {
120     // for now at least all of these enumerators should be in neuter lists and get neutered prior to destruction
121     _ASSERTE(IsNeutered());
122 }
123
124 // COM IUnknown::QueryInterface - provides ICorDebugEnum, IUnknown, and templated EnumInterfaceType
125 //
126 // Arguments:
127 //     riid - IID of the interface to query for
128 //     ppInterface - on output set to a pointer to the desired interface
129 //
130 // Return:
131 //     S_OK for the supported interfaces and E_NOINTERFACE otherwise
132 template< typename ElemType, 
133           typename ElemPublicType,
134           typename EnumInterfaceType,
135           ElemPublicType (*GetPublicType)(ElemType)>
136 HRESULT CordbEnumerator<ElemType,
137                         ElemPublicType,
138                         EnumInterfaceType,
139                         GetPublicType>::QueryInterface(REFIID riid, VOID** ppInterface)
140 {
141     if(riid == __uuidof(ICorDebugEnum))
142     {
143         *ppInterface = static_cast<ICorDebugEnum*>(this);
144         AddRef();
145         return S_OK;
146     }
147     else if(riid == __uuidof(IUnknown))
148     {
149         *ppInterface = static_cast<IUnknown*>(static_cast<CordbBase*>(this));
150         AddRef();
151         return S_OK;
152     }
153     else if(riid == __uuidof(EnumInterfaceType))
154     {
155         *ppInterface = static_cast<EnumInterfaceType*>(this);
156         AddRef();
157         return S_OK;
158     }
159     else
160     {
161         return E_NOINTERFACE;
162     }
163 }
164
165 // COM IUnknown::AddRef()
166 template< typename ElemType, 
167           typename ElemPublicType,
168           typename EnumInterfaceType,
169           ElemPublicType (*GetPublicType)(ElemType)>
170 ULONG CordbEnumerator<ElemType,
171                       ElemPublicType,
172                       EnumInterfaceType,
173                       GetPublicType>::AddRef()
174 {
175     return BaseAddRef();
176 }
177
178 // COM IUnknown::Release()
179 template< typename ElemType, 
180           typename ElemPublicType,
181           typename EnumInterfaceType,
182           ElemPublicType (*GetPublicType)(ElemType)>
183 ULONG CordbEnumerator<ElemType,
184                       ElemPublicType,
185                       EnumInterfaceType,
186                       GetPublicType>::Release()
187 {
188     return BaseRelease();
189 }
190
191 // ICorDebugEnum::Clone
192 // Makes a duplicate of the enumeration. The internal items are copied by value and there is no explicit reference
193 // between the new and old enumerations.
194 //
195 //  Arguments:
196 //    ppEnum - on output filled with a duplicate enumeration
197 //
198 //  Return:
199 //    S_OK if the clone was created succesfully, otherwise some appropriate failing HRESULT
200 template< typename ElemType, 
201           typename ElemPublicType,
202           typename EnumInterfaceType,
203           ElemPublicType (*GetPublicType)(ElemType)>
204 HRESULT CordbEnumerator<ElemType,
205                         ElemPublicType,
206                         EnumInterfaceType,
207                         GetPublicType>::Clone(ICorDebugEnum **ppEnum)
208 {
209     FAIL_IF_NEUTERED(this);
210     VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
211     HRESULT hr = S_OK;
212     EX_TRY
213     {
214         CordbEnumerator<ElemType, ElemPublicType, EnumInterfaceType, GetPublicType>* clone = 
215             new CordbEnumerator<ElemType, ElemPublicType, EnumInterfaceType,GetPublicType>(
216                 GetProcess(), m_items, m_countItems);
217         clone->QueryInterface(__uuidof(ICorDebugEnum), (void**)ppEnum);
218     }
219     EX_CATCH_HRESULT(hr)
220     {
221     }
222     return hr;
223 }
224
225 // ICorDebugEnum::GetCount
226 // Gets the number of items in the the list that is being enumerated
227 //
228 //   Arguments:
229 //     pcelt - on return the number of items being enumerated
230 //
231 //   Return:
232 //     S_OK or failing HRESULTS for other error conditions
233 template< typename ElemType, 
234           typename ElemPublicType,
235           typename EnumInterfaceType,
236           ElemPublicType (*GetPublicType)(ElemType)>
237 HRESULT CordbEnumerator<ElemType,
238                         ElemPublicType,
239                         EnumInterfaceType,
240                         GetPublicType>::GetCount(ULONG *pcelt)
241 {
242     FAIL_IF_NEUTERED(this);
243     VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
244
245     *pcelt = m_countItems;
246     return S_OK;
247 }
248
249 // ICorDebugEnum::Reset
250 // Restarts the enumeration at the beginning of the list
251 //
252 //   Return:
253 //     S_OK or failing HRESULTS for other error conditions
254 template< typename ElemType, 
255           typename ElemPublicType,
256           typename EnumInterfaceType,
257           ElemPublicType (*GetPublicType)(ElemType)>
258 HRESULT CordbEnumerator<ElemType,
259                         ElemPublicType,
260                         EnumInterfaceType,
261                         GetPublicType>::Reset()
262 {
263     FAIL_IF_NEUTERED(this);
264
265     m_nextIndex = 0;
266     return S_OK;
267 }
268
269 // ICorDebugEnum::Skip
270 // Skips over celt items in the enumeration, if celt is greater than the number of remaining items then all
271 // remaining items are skipped.
272 //
273 //   Arguments:
274 //     celt - number of items to be skipped
275 //
276 //   Return:
277 //     S_OK or failing HRESULTS for other error conditions
278 template< typename ElemType, 
279           typename ElemPublicType,
280           typename EnumInterfaceType,
281           ElemPublicType (*GetPublicType)(ElemType)>
282 HRESULT CordbEnumerator<ElemType,
283                         ElemPublicType,
284                         EnumInterfaceType,
285                         GetPublicType>::Skip(ULONG celt)
286 {
287     FAIL_IF_NEUTERED(this);
288
289     m_nextIndex += celt;
290     if(m_nextIndex > m_countItems)
291     {
292         m_nextIndex = m_countItems;
293     }
294     return S_OK;
295 }
296
297 // EnumInterfaceType::Next
298 // Attempts to enumerate the next celt items by copying them in the items array. If fewer than celt
299 // items remain all remaining items are enumerated. In either case pceltFetched indicates the number
300 // of items actually fetched.
301 //
302 //   Arguments:
303 //     celt - the number of enumerated items requested
304 //     items - an array of size celt where the enumerated items will be copied
305 //     pceltFetched - on return, the actual number of items enumerated
306 //
307 //   Return:
308 //     S_OK if all items could be enumerated, S_FALSE if not all the requested items were enumerated,
309 //     failing HRESULTS for other error conditions
310 template< typename ElemType, 
311           typename ElemPublicType,
312           typename EnumInterfaceType,
313           ElemPublicType (*GetPublicType)(ElemType)>
314 HRESULT CordbEnumerator<ElemType,
315                         ElemPublicType,
316                         EnumInterfaceType,
317                         GetPublicType>::Next(ULONG celt,
318                                              ElemPublicType items[],
319                                              ULONG *pceltFetched)
320 {
321     FAIL_IF_NEUTERED(this);
322     VALIDATE_POINTER_TO_OBJECT_ARRAY(items, ElemInterfaceType *,
323         celt, true, true);
324     VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
325
326     if ((pceltFetched == NULL) && (celt != 1))
327     {
328         return E_INVALIDARG;
329     }
330
331     ULONG countFetched;
332     for(countFetched = 0; countFetched < celt && m_nextIndex < m_countItems; countFetched++, m_nextIndex++)
333     {
334         items[countFetched] = GetPublicType(m_items[m_nextIndex]);
335     }
336
337     if(pceltFetched != NULL)
338     {
339         *pceltFetched = countFetched;
340     }
341     
342     return countFetched == celt ? S_OK : S_FALSE;
343 }
344
345 // Neuter
346 // neuters the enumerator and deletes the contents (the contents are not explicitly neutered though)
347 template< typename ElemType, 
348           typename ElemPublicType,
349           typename EnumInterfaceType,
350           ElemPublicType (*GetPublicType)(ElemType)>
351 VOID CordbEnumerator<ElemType,
352                      ElemPublicType,
353                      EnumInterfaceType,
354                      GetPublicType>::Neuter()
355 {
356     delete [] m_items;
357     m_items = NULL;
358     m_countItems = 0;
359     m_nextIndex = 0;
360     CordbBase::Neuter();
361 }