Skip to content

Instantly share code, notes, and snippets.

@urasandesu
Created April 21, 2013 12:52
Show Gist options
  • Save urasandesu/5429490 to your computer and use it in GitHub Desktop.
Save urasandesu/5429490 to your computer and use it in GitHub Desktop.
#pragma once
#ifndef URASANDESU_SWATHE_METADATA_BASECLASSPIMPL_BASETYPEMETADATAPIMPL_HPP
#define URASANDESU_SWATHE_METADATA_BASECLASSPIMPL_BASETYPEMETADATAPIMPL_HPP
#ifndef URASANDESU_SWATHE_METADATA_BASECLASSPIMPL_BASETYPEMETADATAPIMPL_H
#include <Urasandesu/Swathe/Metadata/BaseClassPimpl/BaseTypeMetadataPimpl.h>
#endif
namespace Urasandesu { namespace Swathe { namespace Metadata { namespace BaseClassPimpl {
template<class ApiHolder>
BaseTypeMetadataPimpl<ApiHolder>::BaseTypeMetadataPimpl(type_metadata_label_type *pClass) :
m_pClass(pClass),
m_mdt(mdTokenNil),
m_genericArgsInit(false),
m_filled(false)
{ }
#define SWATHE_DECLARE_BASE_TYPE_METADATA_PIMPL_ADDITIONAL_INSTANTIATION \
template<class ApiHolder>
mdToken BaseTypeMetadataPimpl<ApiHolder>::GetToken() const
{
using Urasandesu::CppAnonym::CppAnonymCOMException;
if (m_mdt == mdTokenNil)
{
if (auto const *pDeclaringType = m_pClass->MapFirstAncestor<type_metadata_label_type>())
{
m_mdt = pDeclaringType->GetToken();
}
else
{
_ASSERTE(!m_fullName.empty());
auto *pAsmMeta = m_pClass->MapFirst<assembly_metadata_label_type>();
auto &comMetaImp = pAsmMeta->GetCOMMetaDataImport();
auto hr = comMetaImp.FindTypeDefByName(m_fullName.c_str(), NULL, &m_mdt);
if (FAILED(hr))
BOOST_THROW_EXCEPTION(CppAnonymCOMException(hr));
}
}
return m_mdt;
}
template<class ApiHolder>
wstring const &BaseTypeMetadataPimpl<ApiHolder>::GetFullName() const
{
if (m_fullName.empty())
FillPropertiesIfNecessary();
return m_fullName;
}
template<class ApiHolder>
bool BaseTypeMetadataPimpl<ApiHolder>::IsGenericParameter() const
{
return TypeFromToken(GetToken()) == mdtGenericParam;
}
template<class ApiHolder>
bool BaseTypeMetadataPimpl<ApiHolder>::IsGenericType() const
{
return !GetGenericArguments().empty();
}
template<class ApiHolder>
bool BaseTypeMetadataPimpl<ApiHolder>::IsGenericTypeDefinition() const
{
if (!IsGenericType())
{
return false;
}
else
{
auto const *pDeclaringType = m_pClass->MapFirstAncestor<type_metadata_label_type>();
return !pDeclaringType;
}
}
template<class ApiHolder>
TempPtrVector<IType const> const &BaseTypeMetadataPimpl<ApiHolder>::GetGenericArguments() const
{
using boost::array;
using Urasandesu::CppAnonym::CppAnonymCOMException;
if (!m_genericArgsInit)
{
auto *pAsm = m_pClass->MapFirst<assembly_metadata_label_type>();
auto &comMetaImp = pAsm->GetCOMMetaDataImport();
auto hEnum = static_cast<HCORENUM>(nullptr);
BOOST_SCOPE_EXIT((&hEnum)(&comMetaImp))
{
if (hEnum)
comMetaImp.CloseEnum(hEnum);
}
BOOST_SCOPE_EXIT_END
auto mdgps = array<mdGenericParam, 16>();
auto count = 0ul;
auto hr = E_FAIL;
auto mdtTarget = GetToken();
do
{
hr = comMetaImp.EnumGenericParams(&hEnum, mdtTarget, mdgps.c_array(), mdgps.size(), &count);
if (FAILED(hr))
BOOST_THROW_EXCEPTION(CppAnonymCOMException(hr));
m_genericArgs.reserve(m_genericArgs.size() + count);
for (auto i = 0u; i < count; ++i)
{
auto pGenericArg = NewGenericArgument(mdgps[i]);
m_genericArgs.push_back(pGenericArg);
}
} while (0 < count);
m_genericArgsInit = true;
}
return m_genericArgs;
}
template<class ApiHolder>
void BaseTypeMetadataPimpl<ApiHolder>::Register(type_metadata_label_type const &type, SIZE_T index)
{
m_typeToIndex[&type] = index;
}
template<class ApiHolder>
void BaseTypeMetadataPimpl<ApiHolder>::SetToken(mdToken mdt)
{
_ASSERTE(!IsNilToken(mdt));
_ASSERTE(IsNilToken(m_mdt));
m_mdt = mdt;
}
template<class ApiHolder>
void BaseTypeMetadataPimpl<ApiHolder>::SetFullName(wstring const &fullName)
{
_ASSERTE(!fullName.empty());
_ASSERTE(m_fullName.empty());
m_fullName = fullName;
}
template<class ApiHolder>
TempPtr<typename BaseTypeMetadataPimpl<ApiHolder>::type_metadata_label_type> BaseTypeMetadataPimpl<ApiHolder>::NewGenericArgument(mdGenericParam mdgp) const
{
auto pType = NewTypeCore();
pType->SetToken(mdgp);
return pType;
}
template<class ApiHolder>
TempPtr<typename BaseTypeMetadataPimpl<ApiHolder>::type_metadata_label_type> BaseTypeMetadataPimpl<ApiHolder>::NewTypeCore() const
{
auto const *pDisp = m_pClass->MapFirst<metadata_dispenser_label_type>();
auto &provider = pDisp->FirstProviderOf<type_metadata_label_type>();
auto &chain = m_pClass->ChainFrom<type_metadata_label_type>();
auto pType = chain.NewObject<type_metadata_label_type>(provider);
auto handler = type_metadata_persisted_handler_label_type();
provider.AddPersistedHandler(pType, handler);
return pType;
}
template<class ApiHolder>
void BaseTypeMetadataPimpl<ApiHolder>::FillPropertiesIfNecessary() const
{
using boost::array;
using Urasandesu::CppAnonym::CppAnonymCOMException;
if (m_filled)
return;
auto *pMod = m_pClass->MapFirst<module_metadata_label_type>();
auto *pAsm = pMod->MapFirst<assembly_metadata_label_type>();
auto &comMetaImp = pAsm->GetCOMMetaDataImport();
auto mdtTarget = GetToken();
if (TypeFromToken(mdtTarget) == mdtTypeRef)
{
BOOST_THROW_EXCEPTION(Urasandesu::CppAnonym::CppAnonymNotImplementedException());
}
else if (TypeFromToken(mdtTarget) == mdtTypeDef)
{
BOOST_THROW_EXCEPTION(Urasandesu::CppAnonym::CppAnonymNotImplementedException());
//WCHAR name[MAX_SYM_NAME] = { 0 };
//ULONG nameSize = sizeof(name);
//DWORD attr = 0;
//mdToken mdtExt = mdTokenNil;
//HRESULT hr = comMetaImp.GetTypeDefProps(mdtTarget, name, nameSize,
// &nameSize, &attr, &mdtExt);
//if (FAILED(hr))
// BOOST_THROW_EXCEPTION(SwatheCOMException(hr));
//m_name = name;
//if (!IsNilToken(mdtExt) &&
// (TypeFromToken(mdtExt) == mdtTypeDef ||
// TypeFromToken(mdtExt) == mdtTypeRef))
//{
// m_pBaseType = pMod->NewType(mdtExt);
//}
//else if (!IsNilToken(mdtExt))
//{
// BOOST_THROW_EXCEPTION(SwatheNotImplementedException());
//}
}
else if (TypeFromToken(mdtTarget) == mdtGenericParam)
{
auto paramIndex = 0ul;
auto paramFlags = 0ul;
auto mdtOwner = mdTokenNil;
auto reserved = 0ul;
auto name = array<WCHAR, MAX_SYM_NAME>();
auto length = 0ul;
auto hr = comMetaImp.GetGenericParamProps(mdtTarget, &paramIndex,
&paramFlags, &mdtOwner,
&reserved, name.c_array(), name.size(),
&length);
if (FAILED(hr))
BOOST_THROW_EXCEPTION(CppAnonymCOMException(hr));
m_fullName = name.data();
}
else
{
BOOST_THROW_EXCEPTION(Urasandesu::CppAnonym::CppAnonymNotImplementedException());
}
m_filled = true;
}
}}}} // namespace Urasandesu { namespace Swathe { namespace Metadata { namespace BaseClassPimpl {
#endif // URASANDESU_SWATHE_METADATA_BASECLASSPIMPL_BASETYPEMETADATAPIMPL_HPP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment