734 lines
17 KiB
C++
734 lines
17 KiB
C++
#ifndef BOOST_RANGE_ATL_HPP
|
|
#define BOOST_RANGE_ATL_HPP
|
|
|
|
|
|
|
|
|
|
// Boost.Range ATL Extension
|
|
//
|
|
// Copyright Shunsuke Sogame 2005-2006.
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
|
|
|
|
|
|
// config
|
|
//
|
|
|
|
|
|
#include <atldef.h> // _ATL_VER
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
#if (_ATL_VER < 0x0700)
|
|
#define BOOST_RANGE_ATL_NO_COLLECTIONS
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
#if (_ATL_VER < 0x0700) // dubious
|
|
#define BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLESTRING)
|
|
#if (_MSC_VER < 1310) // from <boost/regex/mfc.hpp>, but dubious
|
|
#define BOOST_RANGE_ATL_HAS_OLD_CSIMPLESTRING
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// forward declarations
|
|
//
|
|
|
|
|
|
#include <basetyps.h> // IID
|
|
|
|
|
|
namespace ATL {
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
|
|
|
|
// arrays
|
|
//
|
|
template< class E, class ETraits >
|
|
class CAtlArray;
|
|
|
|
template< class E >
|
|
class CAutoPtrArray;
|
|
|
|
template< class I, const IID *piid >
|
|
class CInterfaceArray;
|
|
|
|
|
|
// lists
|
|
//
|
|
template< class E, class ETraits >
|
|
class CAtlList;
|
|
|
|
template< class E >
|
|
class CAutoPtrList;
|
|
|
|
template< class E, class Allocator >
|
|
class CHeapPtrList;
|
|
|
|
template< class I, const IID *piid >
|
|
class CInterfaceList;
|
|
|
|
|
|
// maps
|
|
//
|
|
template< class K, class V, class KTraits, class VTraits >
|
|
class CAtlMap;
|
|
|
|
template< class K, class V, class KTraits, class VTraits >
|
|
class CRBTree;
|
|
|
|
template< class K, class V, class KTraits, class VTraits >
|
|
class CRBMap;
|
|
|
|
template< class K, class V, class KTraits, class VTraits >
|
|
class CRBMultiMap;
|
|
|
|
|
|
// strings
|
|
//
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLESTRING)
|
|
template< class BaseType, bool t_bMFCDLL >
|
|
class CSimpleStringT;
|
|
#else
|
|
template< class BaseType >
|
|
class CSimpleStringT;
|
|
#endif
|
|
|
|
template< class BaseType, class StringTraits >
|
|
class CStringT;
|
|
|
|
template< class StringType, int t_nChars >
|
|
class CFixedStringT;
|
|
|
|
template< class BaseType, const int t_nSize >
|
|
class CStaticString;
|
|
|
|
|
|
#endif // !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
|
|
|
|
// simples
|
|
//
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
|
|
template< class T, class TEqual >
|
|
class CSimpleArray;
|
|
|
|
template< class TKey, class TVal, class TEqual >
|
|
class CSimpleMap;
|
|
|
|
#else
|
|
|
|
template< class T >
|
|
class CSimpleArray;
|
|
|
|
template< class T >
|
|
class CSimpleValArray;
|
|
|
|
template< class TKey, class TVal >
|
|
class CSimpleMap;
|
|
|
|
#endif // !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
|
|
|
|
// pointers
|
|
//
|
|
template< class E >
|
|
class CAutoPtr;
|
|
|
|
template< class T >
|
|
class CComPtr;
|
|
|
|
template< class T, const IID *piid >
|
|
class CComQIPtr;
|
|
|
|
template< class E, class Allocator >
|
|
class CHeapPtr;
|
|
|
|
template< class T >
|
|
class CAdapt;
|
|
|
|
|
|
} // namespace ATL
|
|
|
|
|
|
|
|
|
|
// indirect_iterator customizations
|
|
//
|
|
|
|
|
|
#include <boost/mpl/identity.hpp>
|
|
#include <boost/pointee.hpp>
|
|
|
|
|
|
namespace boost {
|
|
|
|
|
|
template< class E >
|
|
struct pointee< ATL::CAutoPtr<E> > :
|
|
mpl::identity<E>
|
|
{ };
|
|
|
|
template< class T >
|
|
struct pointee< ATL::CComPtr<T> > :
|
|
mpl::identity<T>
|
|
{ };
|
|
|
|
template< class T, const IID *piid >
|
|
struct pointee< ATL::CComQIPtr<T, piid> > :
|
|
mpl::identity<T>
|
|
{ };
|
|
|
|
template< class E, class Allocator >
|
|
struct pointee< ATL::CHeapPtr<E, Allocator> > :
|
|
mpl::identity<E>
|
|
{ };
|
|
|
|
template< class T >
|
|
struct pointee< ATL::CAdapt<T> > :
|
|
pointee<T>
|
|
{ };
|
|
|
|
|
|
} // namespace boost
|
|
|
|
|
|
|
|
|
|
// extended customizations
|
|
//
|
|
|
|
|
|
#include <boost/iterator/indirect_iterator.hpp>
|
|
#include <boost/iterator/zip_iterator.hpp>
|
|
#include <boost/range/detail/microsoft.hpp>
|
|
#include <boost/tuple/tuple.hpp>
|
|
#include <atlbase.h> // CComBSTR
|
|
|
|
|
|
namespace boost { namespace range_detail_microsoft {
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
|
|
|
|
// arrays
|
|
//
|
|
|
|
struct atl_array_functions :
|
|
array_functions
|
|
{
|
|
template< class Iterator, class X >
|
|
Iterator end(X& x) // redefine
|
|
{
|
|
return x.GetData() + x.GetCount(); // no 'GetSize()'
|
|
}
|
|
};
|
|
|
|
|
|
template< class E, class ETraits >
|
|
struct customization< ATL::CAtlArray<E, ETraits> > :
|
|
atl_array_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef E val_t;
|
|
|
|
typedef val_t *mutable_iterator;
|
|
typedef val_t const *const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
template< class E >
|
|
struct customization< ATL::CAutoPtrArray<E> > :
|
|
atl_array_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
// ATL::CAutoPtr/CHeapPtr is no assignable.
|
|
typedef ATL::CAutoPtr<E> val_t;
|
|
typedef val_t *miter_t;
|
|
typedef val_t const *citer_t;
|
|
|
|
typedef indirect_iterator<miter_t> mutable_iterator;
|
|
typedef indirect_iterator<citer_t> const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
template< class I, const IID *piid >
|
|
struct customization< ATL::CInterfaceArray<I, piid> > :
|
|
atl_array_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef ATL::CComQIPtr<I, piid> val_t;
|
|
|
|
typedef val_t *mutable_iterator;
|
|
typedef val_t const *const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
template< class E, class ETraits >
|
|
struct customization< ATL::CAtlList<E, ETraits> > :
|
|
list_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef E val_t;
|
|
|
|
typedef list_iterator<X, val_t> mutable_iterator;
|
|
typedef list_iterator<X const, val_t const> const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
struct indirected_list_functions
|
|
{
|
|
template< class Iterator, class X >
|
|
Iterator begin(X& x)
|
|
{
|
|
typedef typename Iterator::base_type base_t; // == list_iterator
|
|
return Iterator(base_t(x, x.GetHeadPosition()));
|
|
}
|
|
|
|
template< class Iterator, class X >
|
|
Iterator end(X& x)
|
|
{
|
|
typedef typename Iterator::base_type base_t;
|
|
return Iterator(base_t(x, POSITION(0)));
|
|
}
|
|
};
|
|
|
|
|
|
template< class E >
|
|
struct customization< ATL::CAutoPtrList<E> > :
|
|
indirected_list_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef ATL::CAutoPtr<E> val_t;
|
|
typedef list_iterator<X, val_t> miter_t;
|
|
typedef list_iterator<X const, val_t const> citer_t;
|
|
|
|
typedef indirect_iterator<miter_t> mutable_iterator;
|
|
typedef indirect_iterator<citer_t> const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
template< class E, class Allocator >
|
|
struct customization< ATL::CHeapPtrList<E, Allocator> > :
|
|
indirected_list_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef ATL::CHeapPtr<E, Allocator> val_t;
|
|
typedef list_iterator<X, val_t> miter_t;
|
|
typedef list_iterator<X const, val_t const> citer_t;
|
|
|
|
typedef indirect_iterator<miter_t> mutable_iterator;
|
|
typedef indirect_iterator<citer_t> const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
template< class I, const IID *piid >
|
|
struct customization< ATL::CInterfaceList<I, piid> > :
|
|
list_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef ATL::CComQIPtr<I, piid> val_t;
|
|
|
|
typedef list_iterator<X, val_t> mutable_iterator;
|
|
typedef list_iterator<X const, val_t const> const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
// maps
|
|
//
|
|
|
|
struct atl_rb_tree_tag
|
|
{ };
|
|
|
|
template< >
|
|
struct customization< atl_rb_tree_tag > :
|
|
indirected_list_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef typename X::CPair val_t;
|
|
|
|
typedef list_iterator<X, val_t *, val_t *> miter_t;
|
|
typedef list_iterator<X const, val_t const *, val_t const *> citer_t;
|
|
|
|
typedef indirect_iterator<miter_t> mutable_iterator;
|
|
typedef indirect_iterator<citer_t> const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
template< class K, class V, class KTraits, class VTraits >
|
|
struct customization< ATL::CAtlMap<K, V, KTraits, VTraits> > :
|
|
customization< atl_rb_tree_tag >
|
|
{
|
|
template< class Iterator, class X >
|
|
Iterator begin(X& x) // redefine
|
|
{
|
|
typedef typename Iterator::base_type base_t; // == list_iterator
|
|
return Iterator(base_t(x, x.GetStartPosition())); // no 'GetHeadPosition'
|
|
}
|
|
};
|
|
|
|
|
|
// strings
|
|
//
|
|
|
|
struct atl_string_tag
|
|
{ };
|
|
|
|
template< >
|
|
struct customization< atl_string_tag >
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef typename X::PXSTR mutable_iterator;
|
|
typedef typename X::PCXSTR const_iterator;
|
|
};
|
|
|
|
template< class Iterator, class X >
|
|
typename mutable_<Iterator, X>::type begin(X& x)
|
|
{
|
|
return x.GetBuffer(0);
|
|
}
|
|
|
|
template< class Iterator, class X >
|
|
Iterator begin(X const& x)
|
|
{
|
|
return x.GetString();
|
|
}
|
|
|
|
template< class Iterator, class X >
|
|
Iterator end(X& x)
|
|
{
|
|
return begin<Iterator>(x) + x.GetLength();
|
|
}
|
|
};
|
|
|
|
|
|
template< class BaseType, const int t_nSize >
|
|
struct customization< ATL::CStaticString<BaseType, t_nSize> >
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef BaseType const *mutable_iterator;
|
|
typedef mutable_iterator const_iterator;
|
|
};
|
|
|
|
template< class Iterator, class X >
|
|
Iterator begin(X const& x)
|
|
{
|
|
return x;
|
|
}
|
|
|
|
template< class Iterator, class X >
|
|
Iterator end(X const& x)
|
|
{
|
|
return begin<Iterator>(x) + X::GetLength();
|
|
}
|
|
};
|
|
|
|
|
|
#endif // !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
|
|
|
|
template< >
|
|
struct customization< ATL::CComBSTR >
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef OLECHAR *mutable_iterator;
|
|
typedef OLECHAR const *const_iterator;
|
|
};
|
|
|
|
template< class Iterator, class X >
|
|
Iterator begin(X& x)
|
|
{
|
|
return x.operator BSTR();
|
|
}
|
|
|
|
template< class Iterator, class X >
|
|
Iterator end(X& x)
|
|
{
|
|
return begin<Iterator>(x) + x.Length();
|
|
}
|
|
};
|
|
|
|
|
|
// simples
|
|
//
|
|
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
template< class T, class TEqual >
|
|
struct customization< ATL::CSimpleArray<T, TEqual> > :
|
|
#else
|
|
template< class T >
|
|
struct customization< ATL::CSimpleArray<T> > :
|
|
#endif
|
|
array_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef T val_t;
|
|
|
|
typedef val_t *mutable_iterator;
|
|
typedef val_t const *const_iterator;
|
|
};
|
|
};
|
|
|
|
|
|
#if defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
|
|
template< class T >
|
|
struct customization< ATL::CSimpleValArray<T> > :
|
|
array_functions
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef T val_t;
|
|
|
|
typedef val_t *mutable_iterator;
|
|
typedef val_t const *const_iterator;
|
|
};
|
|
};
|
|
|
|
#endif // defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
template< class TKey, class TVal, class TEqual >
|
|
struct customization< ATL::CSimpleMap<TKey, TVal, TEqual> >
|
|
#else
|
|
template< class TKey, class TVal >
|
|
struct customization< ATL::CSimpleMap<TKey, TVal> >
|
|
#endif
|
|
{
|
|
template< class X >
|
|
struct meta
|
|
{
|
|
typedef TKey k_val_t;
|
|
typedef k_val_t *k_miter_t;
|
|
typedef k_val_t const *k_citer_t;
|
|
|
|
typedef TVal v_val_t;
|
|
typedef v_val_t *v_miter_t;
|
|
typedef v_val_t const *v_citer_t;
|
|
|
|
// Topic:
|
|
// 'std::pair' can't contain references
|
|
// because of reference to reference problem.
|
|
|
|
typedef zip_iterator< tuple<k_miter_t, v_miter_t> > mutable_iterator;
|
|
typedef zip_iterator< tuple<k_citer_t, v_citer_t> > const_iterator;
|
|
};
|
|
|
|
template< class Iterator, class X >
|
|
Iterator begin(X& x)
|
|
{
|
|
return Iterator(boost::make_tuple(x.m_aKey, x.m_aVal));
|
|
}
|
|
|
|
template< class Iterator, class X >
|
|
Iterator end(X& x)
|
|
{
|
|
return Iterator(boost::make_tuple(x.m_aKey + x.GetSize(), x.m_aVal + x.GetSize()));
|
|
}
|
|
};
|
|
|
|
|
|
} } // namespace boost::range_detail_microsoft
|
|
|
|
|
|
|
|
|
|
// range customizations
|
|
//
|
|
|
|
|
|
#if !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
|
|
|
|
// arrays
|
|
//
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CAtlArray, 2
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CAutoPtrArray, 1
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CInterfaceArray, (class)(const IID *)
|
|
)
|
|
|
|
|
|
// lists
|
|
//
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CAtlList, 2
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CAutoPtrList, 1
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CHeapPtrList, 2
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CInterfaceList, (class)(const IID *)
|
|
)
|
|
|
|
|
|
//maps
|
|
//
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CAtlMap, 4
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_rb_tree_tag,
|
|
(ATL, BOOST_PP_NIL), CRBTree, 4
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_rb_tree_tag,
|
|
(ATL, BOOST_PP_NIL), CRBMap, 4
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_rb_tree_tag,
|
|
(ATL, BOOST_PP_NIL), CRBMultiMap, 4
|
|
)
|
|
|
|
|
|
// strings
|
|
//
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLESTRING)
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_string_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleStringT, (class)(bool)
|
|
)
|
|
#else
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_string_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleStringT, 1
|
|
)
|
|
#endif
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_string_tag,
|
|
(ATL, BOOST_PP_NIL), CStringT, 2
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::atl_string_tag,
|
|
(ATL, BOOST_PP_NIL), CFixedStringT, (class)(int)
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CStaticString, (class)(const int)
|
|
)
|
|
|
|
|
|
#endif // !defined(BOOST_RANGE_ATL_NO_COLLECTIONS)
|
|
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CComBSTR
|
|
)
|
|
|
|
|
|
// simples
|
|
//
|
|
#if !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleArray, 2
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleMap, 3
|
|
)
|
|
|
|
#else
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleArray, 1
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleMap, 2
|
|
)
|
|
|
|
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
|
|
boost::range_detail_microsoft::using_type_as_tag,
|
|
(ATL, BOOST_PP_NIL), CSimpleValArray, 1
|
|
)
|
|
|
|
#endif // !defined(BOOST_RANGE_ATL_HAS_OLD_CSIMPLE_XXX)
|
|
|
|
|
|
|
|
|
|
#endif
|