#include "stdafx.h"
#include "VBA.h"
#include <atlsafe.h>
#include <vector>
#include <algorithm>
#include <array>
#include <numeric>
#include <ppl.h>
#include <string>
#include <iostream>
#include "comdef.h"
// CVBA
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::ArraySort(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 != 8200) { return E_INVALIDARG; }
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;
long cElements_0 = array_in_out->parray->rgsabound[0].cElements;
long lLbound_1 = 0;
long cElements_1 = 0;
if (cDims == 2) {
lLbound_1 = array_in_out->parray->rgsabound[1].lLbound;
cElements_1 = array_in_out->parray->rgsabound[1].cElements;
}
if (lLbound_0 < 0 || lLbound_1 < 0) { return E_INVALIDARG; } //если границы массивы ниже 0
if (cDims == 2 && delete_duplicates) { return E_INVALIDARG; } //&&-и
if(sort_orientation == 0) {
if (key_1 > cElements_0 + lLbound_0 || (key_1<lLbound_0 && key_1>-1)) { return E_INVALIDARG; }
if (key_2 > cElements_0 + lLbound_0 || (key_2<lLbound_0 && key_2>-1)) { return E_INVALIDARG; }
if (key_3 > cElements_0 + lLbound_0 || (key_3<lLbound_0 && key_3>-1)) { return E_INVALIDARG; }
if (out_array_index && delete_duplicates) { return E_INVALIDARG; } //&&-и
}
else if (sort_orientation == 1) {
if (key_1 > cElements_1 + lLbound_1 || (key_1<lLbound_1 && key_1>-1)) { return E_INVALIDARG; }
if (key_2 > cElements_1 + lLbound_1 || (key_2<lLbound_1 && key_2>-1)) { return E_INVALIDARG; }
if (key_3 > cElements_1 + lLbound_1 || (key_3<lLbound_1 && key_3>-1)) { return E_INVALIDARG; }
if (out_array_index && delete_duplicates) { return E_INVALIDARG; } //&&-и
}
HRESULT hr;
BSTR HUGEP *pbstr;//в с-массив
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){ //если одномерный массив и не выгружаем индексы, просто сортируем, удаляем
std::vector <BSTR> vBSTR(pbstr, pbstr + cElements_0); //передаем в вектор
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);
if (delete_duplicates) {
vBSTR.erase(unique(vBSTR.begin(), vBSTR.end(), comparestring3), vBSTR.end());
} //удаляем дубликаты
for (long i = 0; i < vBSTR.size(); i++) pbstr[i] = vBSTR[i]; //записываем обратно в массив
hr = SafeArrayUnaccessData(array_in_out->parray); //закрываем массив
if (FAILED(hr)) return hr;
if (delete_duplicates) {
array_in_out->parray->rgsabound[0].cElements = vBSTR.size(); //меняем количество элементов
hr = SafeArrayRedim(array_in_out->parray, &array_in_out->parray->rgsabound[0]); //удаляем лишние
if (FAILED(hr)) return hr;
}
}
else if (cDims == 1) { //если одномерный массив и выгружаем индексы
//Pair parallel_sort New - 0.26 (0.28?) сек
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++) outArray1[i+ lLbound_0] = out1[i];
CComVariant varOut(outArray1);
varOut.Detach(index_array_out);
}
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);
//for (long i = 0; i < vBSTR.size(); i++) pbstr[i] = vBSTR[i]; //записываем обратно в массив
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 == -1 && key_3 == -1)||((key_1 == key_2) && (key_2 == key_3))) { //если одно условие
if (sort_orientation == 0) { //если сортировка по строкам
if (key_1 == -1) key_1 = lLbound_0;
long offset = (key_1 - lLbound_0)*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);
}
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) { //если сортировка по столбцам
if (key_1 == -1) key_1 = lLbound_1;
long offset = (key_1 - lLbound_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);
}
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 > -1 || key_3 > -1)) { //если больше условий
if (sort_orientation == 0) { //если сортировка по строкам
if (key_1 == -1) key_1 = lLbound_0;
long offset1 = (key_1 - lLbound_0)*cElements_1; //сдвигаем на заданную размерность
long offset2 = (key_2 - lLbound_0)*cElements_1; //сдвигаем на заданную размерность
long offset3 = (key_3 - lLbound_0)*cElements_1; //сдвигаем на заданную размерность
std::vector<str_index> pairs2(cElements_1);
for (size_t i = 0; i < cElements_1; ++i) {
CComBSTR CComBSTRtmp(pbstr[i + offset1]);
CComBSTRtmp.AppendBSTR(pbstr[i + offset2]);
CComBSTRtmp.AppendBSTR(pbstr[i + offset3]);
pairs2[i] = str_index{ i, CComBSTRtmp.Detach()};
}//сдвигаем на заданную размерность
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);
}
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) { //если сортировка по столбцам
if (key_1 == -1) key_1 = lLbound_1;
long offset1 = (key_1 - lLbound_1); //сдвигаем на заданную размерность
long offset2 = (key_2 - lLbound_1); //сдвигаем на заданную размерность
long offset3 = (key_3 - lLbound_1); //сдвигаем на заданную размерность
//long offset = (key_1 - lLbound_1); //сдвигаем на заданную размерность
std::vector<str_index> pairs2(cElements_0);
for (size_t i = 0; i < cElements_0; ++i) {
CComBSTR CComBSTRtmp(pbstr[i*cElements_1 + offset1]);
CComBSTRtmp.AppendBSTR(pbstr[i*cElements_1 + offset2]);
CComBSTRtmp.AppendBSTR(pbstr[i*cElements_1 + offset3]);
pairs2[i] = str_index{ i, CComBSTRtmp.Detach() };
}//сдвигаем на заданную размерность
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);
}
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;
} |