struct str_index
{
size_t index;
BSTR wstr;
friend bool operator<(const str_index& l, const str_index& r);
friend bool operator==(const str_index& l, const str_index& r);
friend bool operator!=(const str_index& l, const str_index& r) { return !(l == r); }
friend bool operator>(const str_index& l, const str_index& r);
};
bool operator<(const str_index& l, const str_index& r)
{
if (l.wstr == nullptr) return false;// r.wstr != nullptr;
if (r.wstr == nullptr) return true;
return wcscmp(l.wstr, r.wstr) < 0;
}
bool operator==(const str_index& l, const str_index& r)
{
return l.wstr == r.wstr ||
l.wstr != nullptr && r.wstr != nullptr && wcscmp(l.wstr, r.wstr) == 0;
}
bool operator>(const str_index& l, const str_index& r)
{
if (l.wstr == nullptr) return false;
if (r.wstr == nullptr) return true;
return wcscmp(l.wstr, r.wstr) > 0;
}
bool comparestring1(BSTR lhs, BSTR rhs) {
if (lhs == NULL) return false;
if (rhs == NULL) return true;
return wcscmp(lhs, rhs) < 0;
}
bool comparestring2(BSTR lhs, BSTR rhs) {
if (lhs == NULL) return false;
if (rhs == NULL) return true;
return wcscmp(lhs, rhs) > 0;
}
bool comparestring3(BSTR lhs, BSTR rhs) {
if (lhs == NULL && rhs == NULL) return true;
if (lhs == NULL || rhs == NULL) return false;
return wcscmp(lhs, rhs) == 0;
}
STDMETHODIMP CVBA::ArraySortS(VARIANT* array_in_out, VARIANT_BOOL sort_order, LONG key_1, LONG key_2, LONG key_3, LONG sort_orientation, VARIANT_BOOL delete_duplicates, VARIANT_BOOL out_array_index, VARIANT* index_array_out)
{
if (array_in_out->vt != VT_ARRAY | VT_BSTR) { return E_INVALIDARG; }//только массивы BSTR
if (sort_orientation <0 || sort_orientation > 3) { return E_INVALIDARG; } //границы метода
if (sort_orientation >1 && out_array_index) { return E_INVALIDARG; } //массив мндексов выводится для первых двух методов сортировки
long cDims = array_in_out->parray->cDims;
if (cDims > 2) { return E_INVALIDARG; }
long lLbound_0 = array_in_out->parray->rgsabound[0].lLbound;//нижняя граница 1х массив
long cElements_0 = array_in_out->parray->rgsabound[0].cElements;//количество элементов 1х массив/2х массив - столбцов
long lLbound_1 = 0;//нижняя граница 2х массив
long cElements_1 = 0;//количество элементов 2х массив
if (cDims == 2) {
lLbound_1 = array_in_out->parray->rgsabound[1].lLbound;
cElements_1 = array_in_out->parray->rgsabound[1].cElements;
}
if (cDims == 2 && delete_duplicates) { return E_INVALIDARG; } //удаляем дубликаты только в 1х массивах
if (key_1 < 0 || key_2 < 0 || key_3 < 0) { return E_INVALIDARG; }//ключ не может быть отрицательным
if (key_1 == 0 && key_2 > 0 || key_2 == 0 && key_3 > 0) { return E_INVALIDARG; } //задаем ключи по порядку
if(sort_orientation == 0) {
if (key_1 > cElements_0 || key_2 > cElements_0 || key_3 > cElements_0) { return E_INVALIDARG; }//ключ не может быть больше указанной размерности массива
}
else if (sort_orientation == 1) {
if (key_1 > cElements_1 || key_2 > cElements_1 || key_3 > cElements_1) { return E_INVALIDARG; }
}
HRESULT hr;
BSTR HUGEP *pbstr;//в с-массив
//hr = SafeArrayLock(array_in_out->parray); //hr = SafeArrayUnlock(array_in_out->parray)
//if (FAILED(hr)) return hr;
hr = SafeArrayAccessData(array_in_out->parray, (void HUGEP**)&pbstr); //открываем массив для редактирования
if (FAILED(hr)) return hr;
if (cDims == 1 && !out_array_index && !delete_duplicates) { //если сортировать одномерный массив без вывода индексов и без удаления
if (!sort_order) { concurrency::parallel_buffered_sort(pbstr, pbstr + cElements_0, comparestring1); }//0.21 сек
else { concurrency::parallel_buffered_sort(pbstr, pbstr + cElements_0, comparestring2); }
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
else if (cDims == 1 && !out_array_index){ //если одномерный массив и не выгружаем индексы, просто сортируем, удаляем
if (!sort_order) { concurrency::parallel_buffered_sort(pbstr, pbstr + cElements_0, comparestring1); }
else { concurrency::parallel_buffered_sort(pbstr, pbstr + cElements_0, comparestring2); }
long x=0; //удаляем строки, что бы не текла память, нужно ли что-то еще?
for (long i = 1; i < cElements_0; ++i)
{
if (comparestring3(pbstr[i],pbstr[x])) {
SysFreeString(pbstr[i]);
}
else {
pbstr[++x]=pbstr[i];
}
}
array_in_out->parray->rgsabound[0].cElements = x+1; //меняем количество элементов
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
hr = SafeArrayRedim(array_in_out->parray, &array_in_out->parray->rgsabound[0]); //удаляем лишние
if (FAILED(hr)) return hr;
}
else if (cDims == 1) { //если одномерный массив с сортировкой, удалением и выгружаем индексы
std::vector<str_index> pairs1(cElements_0);
for (size_t i = 0; i < cElements_0; ++i) pairs1[i] = str_index{ i+ lLbound_0, pbstr[i] };
if (!sort_order) {
concurrency::parallel_buffered_sort(pairs1.begin(), pairs1.end());
}
else {
concurrency::parallel_buffered_sort(pairs1.begin(), pairs1.end(),
[]( str_index & l, str_index & r)
{return l > r; });
}
std::vector<long> out1(pairs1.size());
std::transform(pairs1.begin(), pairs1.end(), out1.begin(), [](const str_index& i) { return i.index; });
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
CComSafeArray <long> outArray1(out1.size(), lLbound_0);
for (long i = 0; i < out1.size(); i++) { (long)outArray1[i + lLbound_0] = out1[i]; }
CComVariant varOut(outArray1);
varOut.Detach(index_array_out);
outArray1.Destroy();
}
else if (sort_orientation == 2) {//сортировка по всему двухмерному массиву строка-столбец
if (!sort_order) { concurrency::parallel_buffered_sort(pbstr, pbstr + cElements_0 * cElements_1, comparestring1); } //0.21 сек
else { concurrency::parallel_buffered_sort(pbstr, pbstr + cElements_0 * cElements_1, comparestring2); }
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
else if (sort_orientation == 3) { ////сортировка по всему двухмерному массиву столбец-строка)
long cElements_full = cElements_0 * cElements_1;
std::vector <BSTR> vBSTR(pbstr, pbstr + cElements_full); //передаем в вектор
if (!sort_order) concurrency::parallel_buffered_sort(vBSTR.begin(), vBSTR.end(), comparestring1); //0.23(0.30) сек
else concurrency::parallel_buffered_sort(vBSTR.begin(), vBSTR.end(), comparestring2);
long iTmp = 0;
for (long i = 0; i < cElements_1; i++) {
for (long j = 0; j < cElements_full; j=j+cElements_1) {
pbstr[j+i] = vBSTR[iTmp++];//iTmp++;
}
}
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
else if (key_2 == 0){ //если расчет по первому ключу
if (key_1 == 0) { key_1 = 1; }
if (sort_orientation == 0) { //если сортировка по строкам
long offset = (key_1 - 1)*cElements_1; //сдвигаем на заданную размерность
std::vector<str_index> pairs2(cElements_1);
for (size_t i = 0; i < cElements_1; ++i) pairs2[i] = str_index{ i, pbstr[i+ offset] }; //сдвигаем на заданную размерность
if (!sort_order) {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end());
}
else {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end(),
[](str_index & l, str_index & r)
{return l > r; });
}
std::vector<long> out2(pairs2.size());
std::transform(pairs2.begin(), pairs2.end(), out2.begin(), [](const str_index& i) { return i.index; });
if (out_array_index) { //выводим индексы
CComSafeArray <long> outArray2(out2.size(), lLbound_1);
for (long i = 0; i < out2.size(); i++) outArray2[i + lLbound_1] = out2[i]+ lLbound_1;
CComVariant varOut(outArray2);
varOut.Detach(index_array_out);
outArray2.Destroy();
}
else { //сортируем двухмерный массив поодному из измерений (столбец - сортировка строк)
long cElements_full2 = cElements_0 * cElements_1;
std::vector <BSTR> vBSTR(pbstr, pbstr + cElements_full2); //передаем в вектор
for (long i = 0; i < cElements_0; i++) {
for (long j = 0; j < cElements_1; j++) {
pbstr[j + i * cElements_1] = vBSTR[out2[j] + i * cElements_1];
}
}
}
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
else if (sort_orientation == 1) { //если сортировка по столбцам
long offset = (key_1 - 1); //сдвигаем на заданную размерность
std::vector<str_index> pairs2(cElements_0);
for (size_t i = 0; i < cElements_0; ++i) pairs2[i] = str_index{ i, pbstr[i*cElements_1 + offset] }; //сдвигаем на заданную размерность
if (!sort_order) {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end());
}
else {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end(),
[](str_index & l, str_index & r)
{return l > r; });
}
std::vector<long> out2(pairs2.size());
std::transform(pairs2.begin(), pairs2.end(), out2.begin(), [](const str_index& i) { return i.index; });
if (out_array_index) { //выводим индексы
CComSafeArray <long> outArray2(out2.size(), lLbound_0);
for (long i = 0; i < out2.size(); i++) outArray2[i + lLbound_0] = out2[i] + lLbound_0;
CComVariant varOut(outArray2);
varOut.Detach(index_array_out);
outArray2.Destroy();
}
else { //сортируем двухмерный массив поодному из измерений (столбец - сортировка строк)
long cElements_full2 = cElements_0 * cElements_1;
std::vector <BSTR> vBSTR(pbstr, pbstr + cElements_full2); //передаем в вектор
for (long i = 0; i < cElements_1; i++) {
for (long j = 0; j < cElements_0; j++) {
pbstr[i + j * cElements_1] = vBSTR[out2[j] * cElements_1 + i];
}
}
}
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
else if (key_2 > 0 ) { //если расчет по трем ключам
if (key_3 == 0) { key_3 = key_2; }
if (sort_orientation == 0) { //если сортировка по строкам
long offset1 = (key_1 - 1)*cElements_1; //сдвигаем на заданную размерность
long offset2 = (key_2 - 1)*cElements_1; //сдвигаем на заданную размерность
long offset3 = (key_3 - 1)*cElements_1; //сдвигаем на заданную размерность
std::vector<str_index> pairs2(cElements_1);
for (size_t i = 0; i < cElements_1; ++i) {
_bstr_t BSTRtmp(pbstr[i + offset1]);
BSTRtmp= BSTRtmp + _bstr_t(pbstr[i + offset2]);
BSTRtmp = BSTRtmp + _bstr_t(pbstr[i + offset3]);
pairs2[i] = str_index{ i, BSTRtmp};
}
if (!sort_order) {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end());
}
else {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end(),
[](str_index & l, str_index & r)
{return l > r; });
}
std::vector<long> out2(pairs2.size());
std::transform(pairs2.begin(), pairs2.end(), out2.begin(), [](const str_index& i) { return i.index; });
if (out_array_index) { //выводим индексы
CComSafeArray <long> outArray2(out2.size(), lLbound_1);
for (long i = 0; i < out2.size(); i++) outArray2[i + lLbound_1] = out2[i] + lLbound_1;
CComVariant varOut(outArray2);
varOut.Detach(index_array_out);
outArray2.Destroy();
}
else { //сортируем двухмерный массив поодному из измерений (столбец - сортировка строк)
long cElements_full2 = cElements_0 * cElements_1;
std::vector <BSTR> vBSTR(pbstr, pbstr + cElements_full2); //передаем в вектор
for (long i = 0; i < cElements_0; i++) {
for (long j = 0; j < cElements_1; j++) {
pbstr[j + i * cElements_1] = vBSTR[out2[j] + i * cElements_1];
}
}
}
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
else if (sort_orientation == 1) { //если сортировка по столбцам
long offset1 = (key_1 - 1); //сдвигаем на заданную размерность
long offset2 = (key_2 - 1); //сдвигаем на заданную размерность
long offset3 = (key_3 - 1); //сдвигаем на заданную размерность
std::vector<str_index> pairs2(cElements_0);
for (size_t i = 0; i < cElements_0; ++i) {
_bstr_t BSTRtmp(pbstr[i*cElements_1 + offset1]);
BSTRtmp = BSTRtmp + _bstr_t(pbstr[i*cElements_1 + offset2]);
BSTRtmp = BSTRtmp + _bstr_t(pbstr[i*cElements_1 + offset3]);
pairs2[i] = str_index{ i, BSTRtmp };
}
if (!sort_order) {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end());
}
else {
concurrency::parallel_buffered_sort(pairs2.begin(), pairs2.end(),
[](str_index & l, str_index & r)
{return l > r; });
}
std::vector<long> out2(pairs2.size());
std::transform(pairs2.begin(), pairs2.end(), out2.begin(), [](const str_index& i) { return i.index; });
if (out_array_index) { //выводим индексы
CComSafeArray <long> outArray2(out2.size(), lLbound_0);
for (long i = 0; i < out2.size(); i++) outArray2[i + lLbound_0] = out2[i] + lLbound_0;
CComVariant varOut(outArray2);
varOut.Detach(index_array_out);
outArray2.Destroy();
}
else { //сортируем двухмерный массив по одному из измерений (столбец - сортировка строк)
long cElements_full2 = cElements_0 * cElements_1;
std::vector <BSTR> vBSTR(pbstr, pbstr + cElements_full2); //передаем в вектор
for (long i = 0; i < cElements_1; i++) {
for (long j = 0; j < cElements_0; j++) {
pbstr[i + j * cElements_1] = vBSTR[out2[j] * cElements_1 + i];
}
}
}
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
}
else {
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
}
return S_OK;
} |