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