История изменений
Исправление victor79, (текущая версия) :
В результате изысканий и сравнений получил, что наилучший результат дает... Каждый элемент добавляемого массива ищется по сортированному первому массиву.
Любые попытки применить параллельные обходы сортированных массивов только ухудшали результат. И как объединение в новый вектор, и как попытка вставки в текущей же после прохода, оба варианта показывали результат хуже.
Это возможно из-за специфики данных, но я пытался и отсеивать по размеру в среднем равных для складывания. В общем классический merge или комбинация поиск-вставка давал результат не лучше, чем телько поиск-вставка.
В среднем код такой:
template <class K, class D>
void Aggr<K,D>::appendAsInsert_withInsertAfter(const Aggr& o, bool asMove) {
// asMove - два варианта в одном, const Aggr& и Aggr&&
// сортированные данные хранятся в
// mapData, это что-то вроде flat_map<K,D> из boost
// содержит сортированные по ключу складываеммые данные
// накопление позиций, которых нет в текущем объекте,
// но есть в добавляемом - что бы потом сразу все добавить.
MyList<PairForInsert> listForInsert;
Node* preFindPos = begin();
for (const auto &ndSrc: o.mapData) {
const auto& [key,valueSrc] = ndSrc;
// поиск по сортированному массиву от предыдущей позиции
// использование предыдущей позиции улучшает совсем на немного
auto [exists,ndDest] = mapData.findInsPos(key, preFindPos);
preFindPos = ndDest;
if (!exists)
// позиция не нашлась, будет добавлена после цикла
listForInsert += PairForInsert(ndDest, &ndSrc);
else if (!asMove)
ndDest->second += valueSrc;
else
ndDest->second += std::move(const_cast<D&>(valueSrc));
}
// добавление отсутствующих здесь, но присутствующих в добавляемом
// сразу за один проход.
// Если выделенный резерв текущего объекта позволяет,
// то добавляемое совмещается проходом в обратном порядке.
// Если не позволяет, то выделяется новый буфер, и в него
// складывается проходом он начала.
mapData.unsafe_insertListPointers(listForInsert, asMove);
}
Случаи сложений с пустыми объектами отсеюиваются до этой функции как простые копирования или перемещения объектов.
Случай когда добавляемый больше исходного, и добавляемый типа &&, то они меняются местами.
Исправление victor79, :
В результате изысканий и сравнений получил, что наилучший результат дает... Каждый элемент добавляемого массива ищется по сортированному первому массиву.
Любые попытки применить параллельные обходы сортированных массивов только ухудшали результат. И как объединение в новый вектор, и как попытка вставки в текущей же после прохода, оба варианта показывали результат хуже.
Это возможно из-за специфики данных, но я пытался и отсеивать по размеру в среднем равных для складывания. В общем классический merge или комбинация поиск-вставка давал результат не лучше, чем телько поиск-вставка.
В среднем код такой:
void Aggr<K,D>::appendAsInsert_withInsertAfter(const Aggr& o, bool asMove) {
// asMove - два варианта в одном, const Aggr& и Aggr&&
// сортированные данные хранятся в
// mapData, это что-то вроде flat_map<K,D> из boost
// содержит сортированные по ключу складываеммые данные
// накопление позиций, которых нет в текущем объекте,
// но есть в добавляемом - что бы потом сразу все добавить.
MyList<PairForInsert> listForInsert;
Node* preFindPos = begin();
for (const auto &ndSrc: o.mapData) {
const auto& [key,valueSrc] = ndSrc;
// поиск по сортированному массиву от предыдущей позиции
// использование предыдущей позиции улучшает совсем на немного
auto [exists,ndDest] = mapData.findInsPos(key, preFindPos);
preFindPos = ndDest;
if (!exists)
// позиция не нашлась, будет добавлена после цикла
listForInsert += PairForInsert(ndDest, &ndSrc);
else if (!asMove)
ndDest->second += valueSrc;
else
ndDest->second += std::move(const_cast<D&>(valueSrc));
}
// добавление отсутствующих здесь, но присутствующих в добавляемом
// сразу за один проход.
// Если выделенный резерв текущего объекта позволяет,
// то добавляемое совмещается проходом в обратном порядке.
// Если не позволяет, то выделяется новый буфер, и в него
// складывается проходом он начала.
mapData.unsafe_insertListPointers(listForInsert, asMove);
}
Случаи сложений с пустыми объектами отсеюиваются до этой функции как простые копирования или перемещения объектов.
Случай когда добавляемый больше исходного, и добавляемый типа &&, то они меняются местами.
Исходная версия victor79, :
В результате изысканий и сравнений получил, что наилучший результат дает... Каждый элемент добавляемого массива ищется по сортированному первому массиву.
Любые попытки применить параллельные обходы сортированных массивов только ухудшали результат. И как объединение в новый вектор, и как попытка вставки в текущей же после прохода, оба варианта показывали результат хуже. Это возможно из-за специфики данных, но я пытался и отсеивать по размеру в среднем равных для складывания, все равно классический merge давал результат хуже.
В среднем код такой:
void Aggr<K,D>::appendAsInsert_withInsertAfter(const Aggr& o, bool asMove) {
// asMove - два варианта в одном, const Aggr& и Aggr&&
// сортированные данные хранятся в
// mapData, это что-то вроде flat_map<K,D> из boost
// содержит сортированные по ключу складываеммые данные
// накопление позиций, которых нет в текущем объекте,
// но есть в добавляемом - что бы потом сразу все добавить.
MyList<PairForInsert> listForInsert;
Node* preFindPos = begin();
for (const auto &ndSrc: o.mapData) {
const auto& [key,valueSrc] = ndSrc;
// поиск по сортированному массиву от предыдущей позиции
// использование предыдущей позиции улучшает совсем на немного
auto [exists,ndDest] = mapData.findInsPos(key, preFindPos);
preFindPos = ndDest;
if (!exists)
// позиция не нашлась, будет добавлена после цикла
listForInsert += PairForInsert(ndDest, &ndSrc);
else if (!asMove)
ndDest->second += valueSrc;
else
ndDest->second += std::move(const_cast<D&>(valueSrc));
}
// добавление отсутствующих здесь, но присутствующих в добавляемом
// сразу за один проход.
// Если выделенный резерв текущего объекта позволяет,
// то добавляемое совмещается проходом в обратном порядке.
// Если не позволяет, то выделяется новый буфер, и в него
// складывается проходом он начала.
mapData.unsafe_insertListPointers(listForInsert, asMove);
}
Случаи сложений с пустыми объектами отсеюиваются до этой функции как простые копирования или перемещения объектов.
Случай когда добавляемый больше исходного, и добавляемый типа &&, то они меняются местами.