1/*
2 * Copyright (C) 2007 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef COMEnumVariant_h
27#define COMEnumVariant_h
28
29#ifndef NOMINMAX
30#define NOMINMAX
31#endif
32#include <unknwn.h>
33
34
35#include "COMVariantSetter.h"
36
37template<typename ContainerType>
38class COMEnumVariant : public IEnumVARIANT {
39    WTF_MAKE_NONCOPYABLE(COMEnumVariant);
40public:
41    static COMEnumVariant* adopt(ContainerType&);
42    static COMEnumVariant* createInstance(const ContainerType&);
43
44    // IUnknown
45    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
46    virtual ULONG STDMETHODCALLTYPE AddRef();
47    virtual ULONG STDMETHODCALLTYPE Release();
48
49    // IEnumVARIANT
50    virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, VARIANT* rgVar, ULONG* pCeltFetched);
51    virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
52    virtual HRESULT STDMETHODCALLTYPE Reset();
53    virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT** ppEnum);
54
55private:
56    COMEnumVariant()
57        : m_refCount(0)
58    {
59    }
60
61    COMEnumVariant(const ContainerType& container)
62        : m_refCount(0)
63        , m_container(container)
64        , m_currentPos(m_container.begin())
65    {
66    }
67
68    ~COMEnumVariant() {}
69
70    ULONG m_refCount;
71
72    ContainerType m_container;
73    typename ContainerType::const_iterator m_currentPos;
74};
75
76// COMEnumVariant ------------------------------------------------------------------
77template<typename ContainerType>
78COMEnumVariant<typename ContainerType>* COMEnumVariant<ContainerType>::adopt(ContainerType& container)
79{
80    COMEnumVariant* instance = new COMEnumVariant;
81    instance->m_container.swap(container);
82    instance->m_currentPos = instance->m_container.begin();
83    instance->AddRef();
84    return instance;
85}
86
87template<typename ContainerType>
88COMEnumVariant<typename ContainerType>* COMEnumVariant<ContainerType>::createInstance(const ContainerType& container)
89{
90    COMEnumVariant* instance = new COMEnumVariant(container);
91    instance->AddRef();
92    return instance;
93}
94
95// IUnknown ------------------------------------------------------------------------
96template<typename ContainerType>
97HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::QueryInterface(REFIID riid, void** ppvObject)
98{
99    *ppvObject = 0;
100    if (IsEqualGUID(riid, IID_IUnknown))
101        *ppvObject = static_cast<COMEnumVariant*>(this);
102    else if (IsEqualGUID(riid, IID_IEnumVARIANT))
103        *ppvObject = static_cast<COMEnumVariant*>(this);
104    else
105        return E_NOINTERFACE;
106
107    AddRef();
108    return S_OK;
109}
110
111template<typename ContainerType>
112ULONG STDMETHODCALLTYPE COMEnumVariant<ContainerType>::AddRef()
113{
114    return ++m_refCount;
115}
116
117template<typename ContainerType>
118ULONG STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Release()
119{
120    ULONG newRef = --m_refCount;
121    if (!newRef)
122        delete this;
123
124    return newRef;
125}
126
127// IEnumVARIANT --------------------------------------------------------------------
128template<typename ContainerType>
129HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Next(ULONG celt, VARIANT* rgVar, ULONG* pCeltFetched)
130{
131    if (pCeltFetched)
132        *pCeltFetched = 0;
133    if (!rgVar)
134        return E_POINTER;
135    for (unsigned i = 0 ; i < celt; i++)
136        VariantInit(&rgVar[i]);
137
138    for (unsigned i = 0; i < celt; i++) {
139        if (m_currentPos == m_container.end())
140            return S_FALSE;
141
142        COMVariantSetter<ContainerType::ValueType>::setVariant(&rgVar[i], *m_currentPos);
143        ++m_currentPos;
144        if (pCeltFetched)
145            (*pCeltFetched)++;
146    }
147
148    return S_OK;
149}
150
151template<typename ContainerType>
152HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Skip(ULONG celt)
153{
154    for (unsigned i = 0; i < celt; i++) {
155        if (m_currentPos == m_container.end())
156            return S_FALSE;
157
158        ++m_currentPos;
159    }
160    return S_OK;
161}
162
163template<typename ContainerType>
164HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Reset()
165{
166    m_currentPos = m_container.begin();
167    return S_OK;
168}
169
170template<typename ContainerType>
171HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Clone(IEnumVARIANT** ppEnum)
172{
173    if (!ppEnum)
174        return E_POINTER;
175
176    *ppEnum = 0;
177    return E_NOTIMPL;
178}
179
180#endif
181