在C ++中对OLE SafeArray变体进行排序

时间:2019-03-17 02:45:57

标签: arrays sorting c++11 variant safearray

我正在排序OLE SafeArray的变体。我选择使用C ++类型_variant_t来简化事情。

该数组是在VBA的MS Excel中创建的,我将其第一个元素传递给包含以下代码段的C / C ++ DLL。

一切正常,通过DLL的排序速度得到了很好的提高,我得到了想要的正确结果。

但是,我对需要多少代码不满意。我的问题是如何简化这一点?

在Excel VBA中,使用每个元素可以具有不同子类型的Variants数组是很常见的。例如,一个元素可能是BString指针,下一个可能是Double,下一个可能是Currency,下一个是Long,下一个是Variant错误代码。实际上,有很多可能的类型,并且一个SafeArray结构可以很好地一次容纳许多不同的Variant类型。

当我选择在C ++中使用_variant_t类型时,我的希望是排序时会导致排序顺序与MS Excel在对工作表中的数据进行排序时所产生的排序顺序紧密匹配。

A,并非如此。因此,我制作了一个自定义比较器函数,该函数完全类似于Excel提供给std::sort()std::stable_sort()时的排序。但是,比较器功能比我预期的要长得多。

我需要第二个版本的Descending排序,因为Excel排序的确切顺序对于升序和降序都非常令人惊讶,而布尔值的简单反转并没有实现。

所以现在我有两个比较长的比较器函数。

有没有办法以更智能的方式做到这一点?

这是我的两个比较器函数(同样,它们可以完美地工作):

bool CompareVariantsAscending(const _variant_t lhs, const _variant_t rhs) {

    switch (lhs.vt) {

    case VT_R8: case VT_I4: case VT_DATE: case VT_I2: case VT_R4: case VT_CY: case VT_UI1: case VT_DECIMAL: 
        switch (rhs.vt) {
        default:
            return 0 == VarCmp(&(_variant_t)lhs, &(_variant_t)rhs, LOCALE_USER_DEFAULT, NORM_IGNORECASE);
            break;
        case VT_NULL: return false; break;
        case VT_EMPTY: case VT_BSTR: case VT_ERROR: case VT_BOOL: return true; break;
        }

    case VT_BSTR:
        switch (rhs.vt) {
        case VT_BSTR:
            return 0 == VarCmp(&(_variant_t)lhs, &(_variant_t)rhs, LOCALE_USER_DEFAULT, NORM_IGNORECASE);
            break;
        case VT_EMPTY: case VT_ERROR: case VT_BOOL: return true; break;
        default: return false; break;
        }

    case VT_BOOL:
        switch (rhs.vt) {
        case VT_EMPTY: case VT_ERROR: return true; break;
        case VT_BOOL: return lhs.boolVal > rhs.boolVal; break;
        default: return false; break;
        }

    case VT_ERROR:
        switch (rhs.vt) {
        default: return false; break;
        case VT_EMPTY:  return true; break;
        }

    case VT_EMPTY:  // always last
        return false; break;

    case VT_NULL:   // always first
        return true; break; 

    default: return false;

    }

}


bool CompareVariantsDescending(const _variant_t lhs, const _variant_t rhs) {

    switch (lhs.vt) {

    case VT_R8: case VT_I4: case VT_DATE: case VT_I2: case VT_R4: case VT_CY: case VT_UI1: case VT_DECIMAL: 
        switch (rhs.vt) {
        default:
            return 0 < VarCmp(&(_variant_t)lhs, &(_variant_t)rhs, LOCALE_USER_DEFAULT, NORM_IGNORECASE);
            break;
        case VT_NULL: case VT_BSTR: case VT_BOOL: case VT_ERROR: return false; break;
        case VT_EMPTY: return true; break;
        }

    case VT_BSTR:
        switch (rhs.vt) {
        case VT_BSTR:
            return 0 < VarCmp(&(_variant_t)lhs, &(_variant_t)rhs, LOCALE_USER_DEFAULT, NORM_IGNORECASE);
            break;
        case VT_ERROR: case VT_BOOL: case VT_NULL: return false; break;
        default: return true; break;
        }

    case VT_BOOL:
        switch (rhs.vt) {       
        case VT_BOOL: return lhs.boolVal < rhs.boolVal; break;
        case VT_ERROR: case VT_NULL: return false; break;
        default: return true; break;
        }

    case VT_ERROR:
        switch (rhs.vt) {
        default: return true; break;
        case VT_NULL: return false; break;
        case VT_ERROR: return false; break;
        }

    case VT_EMPTY:  // always last
        return false; break;

    case VT_NULL:   // always first
        return true; break; 

    default: return false;

    }

}

请参考下表的示例数据。

第一列显示具有未分类数据的数组元素。

第二列显示如何按升序对数据进行排序。

第三列显示如何按照降序对数据进行排序。

+-----------------+-----------------+-----------------+
|  Data In Array  | Asc Sort Order  | Desc Sort Order |
+-----------------+-----------------+-----------------+
| anchorage       | -78.96          | #NAME?          |
| 123             | -1              | #N/A            |
| FALSE           | 0               | #DIV/0!         |
| #NAME?          | 0.60625         | TRUE            |
| 0               | 1               | FALSE           |
| 2/18/2019 11:55 | 99.01           | zimmer          |
| #N/A            | 123             | Major Tom       |
| 99.01           | 4/15/2017       | anchorage       |
|                 | 2/18/2019 11:55 | ABC             |
| #DIV/0!         |                 | 888.87          |
|                 | $%^%$^          | $%^%$^          |
| ABC             | 888.87          |                 |
| -78.96          | ABC             | 2/18/2019 11:55 |
| Major Tom       | anchorage       | 4/15/2017       |
| TRUE            | Major Tom       | 123             |
| 4/15/2017       | zimmer          | 99.01           |
| zimmer          | FALSE           | 1               |
| 1               | TRUE            | 0.60625         |
|                 | #NAME?          | 0               |
| -1              | #N/A            | -1              |
| 0.60625         | #DIV/0!         | -78.96          |
| 888.87          |                 |                 |
| $%^%$^          |                 |                 |
+-----------------+-----------------+-----------------+

请注意,“ Asc排序顺序”第10位的空白元素为零长度VT_BSTR,而列底部的两个空白元素为VT_EMPTY。

我上面的比较器功能成功产生了这些确切的排序顺序。但是我想知道是否可以更简洁和/或更有效地完成此操作。

比较器函数当前被这样调用:

   std::stable_sort(Data, Data + Rows, CompareVariantsDescending);

0 个答案:

没有答案