blob: 41f2bdc3405774d3db403ce4c3b41b4e6f6c0415 [file] [log] [blame]
// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#pragma once
#include <objbase.h>
template<class IEnumBase, class XXX>
class TEnumXXX : public IEnumBase
{
public:
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE Next(ULONG, XXX*, ULONG*);
HRESULT STDMETHODCALLTYPE Skip(ULONG);
HRESULT STDMETHODCALLTYPE Reset();
//HRESULT STDMETHODCALLTYPE Clone(IEnumBase**);
protected:
TEnumXXX();
TEnumXXX(const TEnumXXX&);
virtual ~TEnumXXX();
virtual HRESULT GetCount(ULONG&) const = 0;
virtual HRESULT GetItem(ULONG, XXX&) = 0;
virtual void ReleaseItems(XXX*, ULONG);
private:
TEnumXXX& operator=(const TEnumXXX&);
ULONG m_cRef;
ULONG m_index;
};
template<class IEnumBase, class XXX>
inline TEnumXXX<IEnumBase, XXX>::TEnumXXX()
: m_cRef(1),
m_index(0)
{
}
template<class IEnumBase, class XXX>
inline TEnumXXX<IEnumBase, XXX>::TEnumXXX(const TEnumXXX& rhs)
: m_cRef(1),
m_index(rhs.m_index)
{
}
template<class IEnumBase, class XXX>
inline TEnumXXX<IEnumBase, XXX>::~TEnumXXX()
{
}
template<class IEnumBase, class XXX>
inline HRESULT TEnumXXX<IEnumBase, XXX>::QueryInterface(
const IID& iid,
void** ppv)
{
if (ppv == 0)
return E_POINTER;
IUnknown*& pUnk = reinterpret_cast<IUnknown*&>(*ppv);
if (iid == __uuidof(IUnknown))
pUnk = this;
else if (iid == __uuidof(IEnumBase))
pUnk = this;
else
{
pUnk = 0;
return E_NOINTERFACE;
}
pUnk->AddRef();
return S_OK;
}
template<class IEnumBase, class XXX>
inline ULONG TEnumXXX<IEnumBase, XXX>::AddRef()
{
return InterlockedIncrement((LONG*)&m_cRef);
}
template<class IEnumBase, class XXX>
inline ULONG TEnumXXX<IEnumBase, XXX>::Release()
{
if (LONG n = InterlockedDecrement((LONG*)&m_cRef))
return n;
delete this;
return 0;
}
template<class IEnumBase, class XXX>
inline HRESULT TEnumXXX<IEnumBase, XXX>::Next(
ULONG c,
XXX* pa,
ULONG* pn)
{
if (pn)
*pn = 0;
if (c == 0) //weird
return S_OK;
if (pa == 0)
return E_POINTER;
if ((c > 1) && (pn == 0))
return E_INVALIDARG;
ULONG index_max;
HRESULT hr = GetCount(index_max);
if (FAILED(hr)) //out of sync
return hr;
if (m_index >= index_max)
return S_FALSE;
const ULONG nn = index_max - m_index;
const ULONG n = (c < nn) ? c : nn;
ULONG i = 0;
for (;;)
{
XXX& item = pa[i];
hr = GetItem(m_index, item);
if (FAILED(hr))
{
ReleaseItems(pa, i);
return hr;
}
++m_index;
if (++i == n)
break;
}
if (pn)
*pn = n;
return (n < c) ? S_FALSE : S_OK;
}
template<class IEnumBase, class XXX>
inline HRESULT TEnumXXX<IEnumBase, XXX>::Skip(ULONG n)
{
ULONG max_index;
const HRESULT hr = GetCount(max_index);
if (FAILED(hr))
return hr;
m_index += n;
return (m_index >= max_index) ? S_FALSE : S_OK;
}
template<class IEnumBase, class XXX>
inline HRESULT TEnumXXX<IEnumBase, XXX>::Reset()
{
m_index = 0;
return S_OK;
}
//template<class IEnumBase, class XXX>
//HRESULT TEnumXXX<IEnumBase, XXX>::Clone(IEnumBase** pp)
//{
// if (pp == 0)
// return E_POINTER;
//
// IEnumBase*& p = *pp;
//
// return
//}
template<class IEnumBase, class XXX>
inline void TEnumXXX<IEnumBase, XXX>::ReleaseItems(XXX*, ULONG)
{
}