You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
15 KiB
470 lines
15 KiB
#if !defined(_WINDOWS_BCL_COMMON_H_INCLUDED_)
|
|
#define _WINDOWS_BCL_COMMON_H_INCLUDED_
|
|
|
|
#pragma once
|
|
|
|
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
bcl_common.h
|
|
|
|
Abstract:
|
|
|
|
Definitions common to all of the Base Class Libraries
|
|
implementation.
|
|
|
|
Author:
|
|
|
|
Michael Grier (MGrier) 2/6/2002
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <memory.h> // for memcpy
|
|
#include <string.h> // for memmove
|
|
#include <limits.h> // for CHAR_BIT
|
|
|
|
namespace BCL {
|
|
|
|
//
|
|
// Macros for error handling in BCL functions
|
|
//
|
|
// Rather than try to break down the purpose of each, here's a couple of
|
|
// examples:
|
|
//
|
|
// TCallDisposition Foo(int i) { // TCallDisposition indicates internal linkage
|
|
// BCL_MAYFAIL_PROLOG // first line of any function that can fail
|
|
// int j;
|
|
// BCL_PARAMETER_CHECK((i >= 0) && (i <= 100));
|
|
// BCL_IFCALLFAILED_EXIT(Bar(i, &j)); // assumes Bar also has internal linkage
|
|
// BCL_ASSERT(j >= 0);
|
|
// BCL_INTERNAL_ERROR_CHECK(i != j);
|
|
// BCL_MAYFAIL_EPILOG_INTERNAL // last line when internal linkage
|
|
// }
|
|
//
|
|
// BOOL Win32ishFoo(int i) {
|
|
// BCL_MAYFAIL_PROLOG
|
|
// BCL_IFCALLFAILED_EXIT(Foo(i));
|
|
// BCL_MAYFAIL_EPILOG_PUBLIC
|
|
// }
|
|
//
|
|
|
|
#define BCL_ORIGINATE_ERROR(_error) do { _bcl_cd = (_error); goto Exit; } while (0)
|
|
|
|
#define BCL_CALLBACK_FAILED do { goto Exit; } while (0)
|
|
|
|
#if _X86_
|
|
#define BCL_DEBUG_BREAK do { __asm { int 3 } } while (0)
|
|
#else
|
|
#define BCL_DEBUG_BREAK do { DebugBreak(VOID); } while (0)
|
|
#endif
|
|
|
|
#define BCL_ASSERTION_FAILURE_ACTION(_szExpr) BCL_DEBUG_BREAK
|
|
|
|
#define BCL_ASSERT(_e) do { if (!(_e)) { BCL_ASSERTION_FAILURE_ACTION(#_e); } } while (0)
|
|
|
|
#define BCL_COMPILE_TIME_ASSERT(_e) typedef char __c_assert[(_e) ? 1 : -1]
|
|
|
|
#define BCL_INTERNAL_ERROR_FAILURE_ACTION(_szExpr) do { BCL_DEBUG_BREAK; _bcl_cd = TCallDisposition::InternalError_RuntimeCheck(); goto Exit; } while (0)
|
|
|
|
#define BCL_INTERNAL_ERROR_CHECK(_e) do { if (!(_e)) { BCL_INTERNAL_ERROR_FAILURE_ACTION(#_e); } } while (0)
|
|
|
|
#define BCL_MAYFAIL_PROLOG \
|
|
TCallDisposition _bcl_cd = TCallDisposition::InternalError_EpilogSkipped();
|
|
|
|
#define BCL_MAYFAIL_EPILOG_INTERNAL \
|
|
_bcl_cd = TCallDisposition::Success(); \
|
|
if (false) { goto Exit; } \
|
|
Exit: \
|
|
return _bcl_cd;
|
|
|
|
#define BCL_MAYFAIL_EPILOG_PUBLIC \
|
|
_bcl_cd = TCallDisposition::Success(); \
|
|
if (false) { goto Exit; } \
|
|
Exit: \
|
|
return _bcl_cd.OnPublicReturn();
|
|
|
|
#define BCL_NOFAIL_PROLOG /* nothing */
|
|
#define BCL_NOFAIL_EPILOG /* nothing */
|
|
|
|
#define BCL_PARAMETER_CHECK_FAILURE_ACTION(_p) do { _bcl_cd = TCallDisposition::BadParameter(); goto Exit; } while (0)
|
|
|
|
#define BCL_PARAMETER_CHECK(_p) do { if (!(_p)) { BCL_PARAMETER_CHECK_FAILURE_ACTION(_p); } } while (0)
|
|
|
|
#define BCL_IFCALLFAILED_EXIT(_e) do { const TCallDisposition _bcl_cd_temp = (_e); if (_bcl_cd_temp.DidFail()) { _bcl_cd = _bcl_cd_temp; goto Exit; } } while (0)
|
|
|
|
#define BCL_NUMBER_OF(_x) (sizeof(_x) / sizeof((_x)[0]))
|
|
|
|
template <typename T, typename TSizeT> class CConstantPointerAndCountPair;
|
|
template <typename T, typename TSizeT> class CMutablePointerAndCountPair;
|
|
template <typename T, typename TSizeT> class CConstantPointerAndCountRefPair;
|
|
template <typename T, typename TSizeT> class CMutablePointerAndCountRefPair;
|
|
|
|
template <typename T, typename TSizeT>
|
|
class CConstantPointerAndCountPair
|
|
{
|
|
public:
|
|
typedef const T *TConstantArray;
|
|
typedef T *TMutableArray;
|
|
typedef T TPointee;
|
|
typedef TSizeT TCount;
|
|
|
|
inline CConstantPointerAndCountPair() : m_prg(NULL), m_c(0) { }
|
|
inline CConstantPointerAndCountPair(TConstantArray prg, TSizeT c) : m_prg(prg), m_c(c) { }
|
|
inline CConstantPointerAndCountPair(const CMutablePointerAndCountPair<T, TSizeT> &r) : m_prg(r.m_prg), m_c(r.m_c) { }
|
|
inline CConstantPointerAndCountPair(const CConstantPointerAndCountPair &r) : m_prg(r.m_prg), m_c(r.m_c) { }
|
|
inline ~CConstantPointerAndCountPair() { }
|
|
|
|
CConstantPointerAndCountPair &operator =(const CConstantPointerAndCountPair &r)
|
|
{
|
|
m_prg = r.m_prg;
|
|
m_c = r.m_c;
|
|
return *this;
|
|
}
|
|
|
|
CConstantPointerAndCountPair &operator =(const CMutablePointerAndCountPair<T, TSizeT> &r)
|
|
{
|
|
m_prg = r.m_prg;
|
|
m_c = r.m_c;
|
|
return *this;
|
|
}
|
|
|
|
inline TConstantArray GetPointer() const { return m_prg; }
|
|
inline TSizeT GetCount() const { return m_c; }
|
|
|
|
inline TConstantArray &Pointer() { return m_prg; }
|
|
inline TSizeT &Count() { return m_c; }
|
|
|
|
inline void SetCount(TSizeT c) { m_c = c; }
|
|
inline void SetPointer(TConstantArray prg) { m_prg = prg; }
|
|
|
|
inline void SetPointerAndCount(TConstantArray prg, TSizeT c) { m_prg = prg; m_c = c; }
|
|
|
|
inline bool Valid() const { return (m_prg != NULL) || (m_c == 0); }
|
|
|
|
inline CConstantPointerAndCountPair GetOffsetPair(TSizeT n) { return CConstantPointerAndCountPair(m_prg + n, m_c - n); }
|
|
|
|
protected:
|
|
TConstantArray m_prg;
|
|
TSizeT m_c;
|
|
}; // BCL::CConstantPointerAndCountPair<T, TSizeT>
|
|
|
|
template <typename T, typename TSizeT>
|
|
class CMutablePointerAndCountPair : public CConstantPointerAndCountPair<T, TSizeT>
|
|
{
|
|
public:
|
|
typedef const T *TConstantArray;
|
|
typedef T *TMutableArray;
|
|
|
|
inline CMutablePointerAndCountPair() { }
|
|
inline CMutablePointerAndCountPair(TMutableArray prg, TSizeT c) : CConstantPointerAndCountPair<T, TSizeT>(prg, c) { }
|
|
inline ~CMutablePointerAndCountPair() { }
|
|
|
|
using CConstantPointerAndCountPair<T, TSizeT>::Valid;
|
|
|
|
CMutablePointerAndCountPair &operator =(const CMutablePointerAndCountPair &r)
|
|
{
|
|
m_prg = r.m_prg;
|
|
m_c = r.m_c;
|
|
return *this;
|
|
}
|
|
|
|
inline TMutableArray GetPointer() const { return const_cast<TMutableArray>(m_prg); }
|
|
inline TSizeT GetCount() const { return m_c; }
|
|
|
|
inline TMutableArray &Pointer() { return const_cast<TMutableArray &>(m_prg); }
|
|
inline TSizeT &Count() { return m_c; }
|
|
|
|
inline void SetPointer(TMutableArray prg) { m_prg = prg; }
|
|
inline void SetCount(TSizeT c) { m_c = c; }
|
|
|
|
inline void SetPointerAndCount(TMutableArray prg, TSizeT c) { m_prg = prg; m_c = c; }
|
|
}; // BCL::CMutablePointerAndCountPair<T, TSizeT>
|
|
|
|
template <typename T, typename TSizeT>
|
|
class CConstantPointerAndCountRefPair
|
|
{
|
|
public:
|
|
typedef const T *TConstantArray;
|
|
typedef T *TMutableArray;
|
|
typedef T TPointee;
|
|
typedef TSizeT TCount;
|
|
|
|
inline CConstantPointerAndCountRefPair(TConstantArray &rprg, TSizeT &rc) : m_rprg(rprg), m_rc(rc) { }
|
|
inline CConstantPointerAndCountRefPair(const CMutablePointerAndCountRefPair<T, TSizeT> &r) : m_rprg(r.m_rprg), m_rc(r.m_rc) { }
|
|
inline CConstantPointerAndCountRefPair(const CConstantPointerAndCountRefPair &r) : m_rprg(r.m_rprg), m_rc(r.m_rc) { }
|
|
inline ~CConstantPointerAndCountRefPair() { }
|
|
|
|
inline CConstantPointerAndCountRefPair &operator =(const CConstantPointerAndCountPair<T, TSizeT> &r)
|
|
{
|
|
m_rprg = r.GetPointer();
|
|
m_rc = r.GetCount();
|
|
return *this;
|
|
}
|
|
|
|
inline operator CConstantPointerAndCountPair<T, TSizeT>() const { return BCL::CConstantPointerAndCountPair<T, TSizeT>(m_rprg, m_rc); }
|
|
|
|
inline TConstantArray GetPointer() const { return m_rprg; }
|
|
inline TSizeT GetCount() const { return m_rc; }
|
|
|
|
inline TConstantArray &Pointer() { return m_rprg; }
|
|
inline TSizeT &Count() { return m_rc; }
|
|
|
|
inline void SetCount(TSizeT c) { m_rc = c; }
|
|
inline void SetPointer(TConstantArray prg) { m_rprg = prg; }
|
|
|
|
inline void SetPointerAndCount(TConstantArray prg, TSizeT c) { m_rprg = prg; m_rc = c; }
|
|
|
|
inline bool Valid() const { return (m_rprg != NULL) || (m_rc == 0); }
|
|
|
|
inline CConstantPointerAndCountPair GetOffsetPair(TSizeT n) { return CConstantPointerAndCountPair(m_rprg + n, m_rc - n); }
|
|
|
|
protected:
|
|
TConstantArray &m_rprg;
|
|
TSizeT &m_rc;
|
|
}; // BCL::CConstantPointerAndCountRefPair<T, TSizeT>
|
|
|
|
template <typename T, typename TSizeT>
|
|
class CMutablePointerAndCountRefPair : public CConstantPointerAndCountRefPair<T, TSizeT>
|
|
{
|
|
public:
|
|
typedef const T *TConstantArray;
|
|
typedef T *TMutableArray;
|
|
|
|
inline CMutablePointerAndCountRefPair(TMutableArray &rprg, TSizeT &rc) : CConstantPointerAndCountRefPair<T, TSizeT>(rprg, rc) { }
|
|
inline ~CMutablePointerAndCountRefPair() { }
|
|
|
|
using CConstantPointerAndCountRefPair<T, TSizeT>::Valid;
|
|
|
|
CMutablePointerAndCountRefPair &operator =(const CMutablePointerAndCountPair &r)
|
|
{
|
|
m_rprg = r.GetPointer();
|
|
m_rc = r.GetCount();
|
|
return *this;
|
|
}
|
|
|
|
inline operator CMutablePointerAndCountPair<T, TSizeT>() const { return BCL::CMutablePointerAndCountPair<T, TSizeT>(m_rprg, m_rc); }
|
|
|
|
inline TMutableArray GetPointer() const { return const_cast<TMutableArray>(m_rprg); }
|
|
inline TSizeT GetCount() const { return m_c; }
|
|
|
|
inline TMutableArray &Pointer() { return const_cast<TMutableArray &>(m_rprg); }
|
|
inline TSizeT &Count() { return m_c; }
|
|
|
|
inline void SetPointer(TMutableArray prg) { m_rprg = prg; }
|
|
inline void SetCount(TSizeT c) { m_rc = c; }
|
|
|
|
inline void SetPointerAndCount(TMutableArray prg, TSizeT c) { m_rprg = prg; m_rc = c; }
|
|
}; // BCL::CMutablePointerAndCountRefPair<T, TSizeT>
|
|
|
|
#pragma intrinsic(memcmp)
|
|
#pragma intrinsic(memcpy)
|
|
|
|
inline
|
|
bool
|
|
__fastcall
|
|
IsMemoryEqual(
|
|
const void *pv1,
|
|
const void *pv2,
|
|
size_t cb
|
|
)
|
|
{
|
|
return (memcmp(pv1, pv2, cb) == 0);
|
|
} // BCL::IsMemoryEqual
|
|
|
|
template <typename T, typename TSizeT>
|
|
inline
|
|
bool
|
|
__fastcall
|
|
IsMemoryEqual(
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpair1,
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpair2
|
|
)
|
|
{
|
|
return ((rpair1.GetCount() == rpair2.GetCount()) &&
|
|
(BCL::IsMemoryEqual(
|
|
rpair1.GetPointer(),
|
|
rpair2.GetPointer(),
|
|
rpair1.GetCount() * sizeof(T))));
|
|
} // BCL::IsMemoryEqual
|
|
|
|
template <typename TComparisonResult>
|
|
inline
|
|
TComparisonResult
|
|
__fastcall
|
|
CompareBytes(
|
|
const void *pv1,
|
|
const void *pv2,
|
|
size_t cb
|
|
)
|
|
{
|
|
int i = memcmp(pv1, pv2, cb);
|
|
if (i < 0)
|
|
return TComparisonResult::LessThan();
|
|
else if (i == 0)
|
|
return TComparisonResult::EqualTo();
|
|
else
|
|
return TComparisonResult::GreaterThan();
|
|
} // BCL::CompareBytes
|
|
|
|
template <typename T, typename TSizeT, typename TComparisonResult>
|
|
inline
|
|
TComparisonResult
|
|
__fastcall
|
|
CompareBytes(
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpair1,
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpair2
|
|
)
|
|
{
|
|
TComparisonResult cr = BCL::CompareBytes<TComparisonResult>(
|
|
rpair1.GetPointer(),
|
|
rpair2.GetPointer(),
|
|
((rpair1.GetCount() < rpair2.GetCount()) ? rpair1.GetCount() : rpair2.GetCount()) * sizeof(T));
|
|
if (cr.IsEqualTo())
|
|
{
|
|
if (rpair1.GetCount() < rpair2.GetCount())
|
|
cr.SetLessThan();
|
|
else if (rpair1.GetCount() > rpair2.GetCount())
|
|
cr.SetGreaterThan();
|
|
}
|
|
return cr;
|
|
} // BCL::CompareBytes
|
|
|
|
inline
|
|
void
|
|
__fastcall
|
|
CopyBytes(
|
|
void *pvDestination,
|
|
const void *pvSource,
|
|
size_t cbToCopy
|
|
)
|
|
{
|
|
memcpy(pvDestination, pvSource, cbToCopy);
|
|
} // BCL::CopyBytes
|
|
|
|
template <typename T, typename TSizeT>
|
|
inline
|
|
void
|
|
__fastcall
|
|
CopyBytes(
|
|
const CMutablePointerAndCountPair<T, TSizeT> &rpairOut,
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpairIn
|
|
)
|
|
{
|
|
BCL_ASSERT(rpairOut.GetCount() >= rpairIn.GetCount());
|
|
// Be defensive...
|
|
BCL::CopyBytes(
|
|
rpairOut.GetPointer(),
|
|
rpairIn.GetPointer(),
|
|
(rpairIn.GetCount() > rpairOut.GetCount()) ? rpairOut.GetCount() : rpairIn.GetCount());
|
|
} // BCL::CopyBytes
|
|
|
|
inline
|
|
void
|
|
__fastcall
|
|
MoveBytes(
|
|
void *pvDestination,
|
|
const void *pvSource,
|
|
size_t cbToCopy
|
|
)
|
|
{
|
|
memmove(pvDestination, pvSource, cbToCopy);
|
|
} // BCL::MoveBytes
|
|
|
|
template <typename T, typename TSizeT>
|
|
inline
|
|
void
|
|
__fastcall
|
|
MoveBytes(
|
|
const CMutablePointerAndCountPair<T, TSizeT> &rpairOut,
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpairIn
|
|
)
|
|
{
|
|
BCL_ASSERT(rpairOut.GetCount() >= rpairIn.GetCount());
|
|
// Be defensive...
|
|
BCL::MoveBytes(
|
|
rpairOut.GetPointer(),
|
|
rpairIn.GetPointer(),
|
|
(rpairIn.GetCount() > rpairOut.GetCount()) ? rpairOut.GetCount() : rpairIn.GetCount());
|
|
} // BCL::MoveBytes
|
|
|
|
template <typename T, typename TSizeT>
|
|
inline
|
|
void
|
|
__fastcall
|
|
CopyBytesAndAdvance(
|
|
CMutablePointerAndCountPair<T, TSizeT> &rpairOut,
|
|
const CConstantPointerAndCountPair<T, TSizeT> &rpairIn
|
|
)
|
|
{
|
|
const TSizeT cToCopy = (rpairIn.GetCount() > rpairOut.GetCount()) ? rpairOut.GetCount() : rpairIn.GetCount();
|
|
|
|
BCL_ASSERT(cToCopy == rpairIn.GetCount());
|
|
|
|
BCL::CopyBytes(
|
|
rpairOut.GetPointer(),
|
|
rpairIn.GetPointer(),
|
|
cToCopy * sizeof(T));
|
|
rpairOut.SetPointerAndCount(rpairOut.GetPointer() + cToCopy, rpairOut.GetCount() - cToCopy);
|
|
} // BCL::CopyBytesAndAdvance
|
|
|
|
template <typename T, typename TCallDisposition>
|
|
inline TCallDisposition __fastcall AddWithOverflowCheck(T left, T right, T& output)
|
|
{
|
|
const T Result = left + right;
|
|
|
|
if ((Result < left) || (Result < right))
|
|
return TCallDisposition::ArithmeticOverflow();
|
|
|
|
output = Result;
|
|
return TCallDisposition::Success();
|
|
}
|
|
|
|
template <typename T, typename TCallDisposition>
|
|
inline TCallDisposition __fastcall MultiplyWithOverflowCheck(T factor1, T factor2, T &rproduct)
|
|
{
|
|
//
|
|
// Ok, this is somewhat tricky for SIZE_T. Here's what we'll assume:
|
|
//
|
|
// We'll assume that we can take each factor and split it into two halves
|
|
// by using (CHAR_BITS * sizeof(SIZE_T) / 2). (This of course assumes that
|
|
// one or the other is even which is a pretty safe bet.)
|
|
//
|
|
|
|
#define HALF_T_BITS(_t) (CHAR_BIT * sizeof(_t) / 2)
|
|
#define HALF_T_MASK(_t) ((1 << HALF_T_BITS(_t)) - 1)
|
|
|
|
const T lowFactor1 = factor1 & HALF_T_MASK(T);
|
|
const T highFactor1 = (factor1 >> HALF_T_BITS(T)) & HALF_T_MASK(T);
|
|
const T lowFactor2 = factor2 & HALF_T_MASK(T);
|
|
const T highFactor2 = (factor2 >> HALF_T_BITS(T)) & HALF_T_MASK(T);
|
|
|
|
// If both have non-zero high halves, we definitely have an overflow
|
|
|
|
if ((highFactor1 != 0) && (highFactor2 != 0))
|
|
return TCallDisposition::ArithmeticOverflow();
|
|
|
|
const T crossproduct1 = (lowFactor1 * highFactor2);
|
|
const T crossproduct2 = (lowFactor2 * highFactor1);
|
|
const T crossproductsum = (crossproduct1 + crossproduct2);
|
|
|
|
if ((crossproductsum < crossproduct1) || (crossproductsum < crossproduct2))
|
|
return TCallDisposition::ArithmeticOverflow();
|
|
|
|
// We're going to have to shift the cross product sum by HALF_SIZE_T_BITS
|
|
// so let's make sure we don't lose anything.
|
|
if ((crossproductsum >> HALF_T_BITS(T)) != 0)
|
|
return TCallDisposition::ArithmeticOverflow();
|
|
|
|
// Ok, we should be OK...
|
|
rproduct = (crossproductsum << HALF_T_BITS(T)) + (lowFactor1 * lowFactor2);
|
|
return TCallDisposition::Success();
|
|
}
|
|
|
|
}; // namespace BCL
|
|
|
|
#endif // !defined(_WINDOWS_BCL_COMMON_H_INCLUDED_)
|