TrySZBinarySearch在哪里实施?

时间:2013-08-16 17:06:56

标签: c# .net extern reference-implementation

虽然我正在研究一些微观性能技术,但我在array.cs file中在.net框架中遇到了对二进制搜索函数的外部引用。

private static extern bool TrySZBinarySearch(Array sourceArray, int sourceIndex, int count, Object value, out int retVal); 

我在哪里可以找到此功能的文档?或者更好,它是如何实现的? 为什么.net中有这么多的SZ?

private static extern bool TrySZIndexOf(Array sourceArray, int sourceIndex, int count, Object value, out int retVal); 

private static extern bool TrySZLastIndexOf(Array sourceArray, int sourceIndex, int count, Object value, out int retVal);

sealed class SZArrayHelper { ... }

2 个答案:

答案 0 :(得分:5)

    [System.Security.SecurityCritical]  // auto-generated
    [ResourceExposure(ResourceScope.None)]
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    private static extern bool TrySZBinarySearch(Array sourceArray, 
        int sourceIndex, int count, Object value, out int retVal);

这是从参考源检索到的声明。其中包含.NET框架的绝大部分源代码。您可以下载it here

[MethodImpl(MethodImplOptions.InternalCall)]赋予的方法是用C ++编写的,包含在CLR中。 CLR的源代码也可以从SSCLI20获得,SSCLI20是CLR的共享源版本,旨在帮助将.NET移植到其他操作系统。它有点过时了,因为它是在.NET 2.0时间框架发布的,但许多主辅助函数仍然是准确的。您可以下载it here

你会在clr / src / vm / ecall.cpp中找到TrySZBinarySearch,这是寻找InternalCall方法的第一个地方。您将看到它映射到ArrayHelper :: TrySZBinarySearch()C ++方法,您将在clr / src / vm / comarrayhelper.cpp中找到它

没有什么特别有趣的,只是一个专门用于各种简单值类型的纯二进制搜索算法。你可以在this answer中找到它用C ++而不是C#编写的原因。

SZ是单维零基础的缩写,是从C#array []声明中获得的那种数组。在C#中更好地称为“向量”。由于它是如此常用,因此经过微量优化。

更新:今天使用github提供的CoreCLR源代码更容易看到,函数is here

答案 1 :(得分:1)

[MethodImplAttribute(MethodImplOptions.InternalCall)]
方法声明上的

...表示这是作为本机方法(即通常为C ++ /汇编)实现的,而不是在.NET中实现(例如C#)。你会在SSCLI的clr \ src \ _vm \ comarrayhelpers.cpp中找到实现(留下深入调查作为读者的练习 - 汉斯帕斯特已经解释了你会发现什么比我能找到的更好):

FCIMPL5(FC_BOOL_RET, ArrayHelper::TrySZBinarySearch, ArrayBase * array, UINT32 index, UINT32 count, Object * value, INT32 * retVal)
    WRAPPER_CONTRACT;
    STATIC_CONTRACT_SO_TOLERANT;

    VALIDATEOBJECTREF(array);
    _ASSERTE(array != NULL);

    if (array->GetRank() != 1 || array->GetLowerBoundsPtr()[0] != 0)
        FC_RETURN_BOOL(FALSE);

    _ASSERTE(retVal != NULL);
    _ASSERTE(index <= array->GetNumComponents());
    _ASSERTE(count <= array->GetNumComponents());
    _ASSERTE(array->GetNumComponents() >= index + count);
    *retVal = 0xdeadbeef;  // Initialize the return value.
    // value can be NULL, but of course, will not be in primitive arrays.
    TypeHandle arrayTH = array->GetArrayElementTypeHandle();
    const CorElementType arrayElType = arrayTH.GetVerifierCorElementType();
    if (!CorTypeInfo::IsPrimitiveType(arrayElType))
        FC_RETURN_BOOL(FALSE);
    // Handle special case of looking for a NULL object in a primitive array.
    if (value == NULL) {
        *retVal = -1;
        FC_RETURN_BOOL(TRUE);
    }

    TypeHandle valueTH = value->GetTypeHandle();
    if (arrayTH != valueTH)
        FC_RETURN_BOOL(FALSE);

    switch(arrayElType) {
    case ELEMENT_TYPE_I1:
        *retVal = ArrayHelpers<I1>::BinarySearchBitwiseEquals((I1*) array->GetDataPtr(), index, count, *(I1*)value->UnBox());
        break;

    case ELEMENT_TYPE_U1:
    case ELEMENT_TYPE_BOOLEAN:
        *retVal = ArrayHelpers<U1>::BinarySearchBitwiseEquals((U1*) array->GetDataPtr(), index, count, *(U1*)value->UnBox());
        break;

    case ELEMENT_TYPE_I2:
        *retVal = ArrayHelpers<I2>::BinarySearchBitwiseEquals((I2*) array->GetDataPtr(), index, count, *(I2*)value->UnBox());
        break;

    case ELEMENT_TYPE_U2:
    case ELEMENT_TYPE_CHAR:
        *retVal = ArrayHelpers<U2>::BinarySearchBitwiseEquals((U2*) array->GetDataPtr(), index, count, *(U2*)value->UnBox());
        break;

    case ELEMENT_TYPE_I4:
        *retVal = ArrayHelpers<I4>::BinarySearchBitwiseEquals((I4*) array->GetDataPtr(), index, count, *(I4*)value->UnBox());
        break;

    case ELEMENT_TYPE_U4:
        *retVal = ArrayHelpers<U4>::BinarySearchBitwiseEquals((U4*) array->GetDataPtr(), index, count, *(U4*)value->UnBox());
        break;

    case ELEMENT_TYPE_R4:
        *retVal = ArrayHelpers<R4>::BinarySearchBitwiseEquals((R4*) array->GetDataPtr(), index, count, *(R4*)value->UnBox());
        break;

    case ELEMENT_TYPE_I8:
        *retVal = ArrayHelpers<I8>::BinarySearchBitwiseEquals((I8*) array->GetDataPtr(), index, count, *(I8*)value->UnBox());
        break;

    case ELEMENT_TYPE_U8:
        *retVal = ArrayHelpers<U8>::BinarySearchBitwiseEquals((U8*) array->GetDataPtr(), index, count, *(U8*)value->UnBox());
        break;

    case ELEMENT_TYPE_R8:
        *retVal = ArrayHelpers<R8>::BinarySearchBitwiseEquals((R8*) array->GetDataPtr(), index, count, *(R8*)value->UnBox());
        break;

    case ELEMENT_TYPE_I:
    case ELEMENT_TYPE_U:
        // In V1.0, IntPtr & UIntPtr are not fully supported types.  They do 
        // not implement IComparable, so searching & sorting for them should
        // fail.  In V1.1 or V2.0, this should change.  --                                   
        FC_RETURN_BOOL(FALSE);

    default:
        _ASSERTE(!"Unrecognized primitive type in ArrayHelper::TrySZBinarySearch");
        FC_RETURN_BOOL(FALSE);
    }
    FC_RETURN_BOOL(TRUE);
FCIMPLEND

各种方法名称中的SZ指的是“ S 单个维度, Z 基于ero”的数组。这就是你将得到的东西,例如:

int[] myArray;

MyObject[] myArray;

...与.NET中的另一种更通用的数组相反,它可以是多维的:

int[,] myArray;

...或者可能有不同于0的下限:

// Creates a single-dimensional array of size 10 with a lower bound of 5
// - as far as I recall C# doesn't have any dedicated declaration for this.
// It's mainly there to support other languages:
Array myArray = Array.CreateInstance(
   typeof(int), 
   new int[] { 10 }, 
   new int[] { 5 }
);

SZ阵列性能更高,更优化,因此通常更受欢迎。这就是为什么你会在CLR代码中看到这么多对它们的引用(因此在上面的代码中早期检查排名和下限的原因)。