В C ++ 23, std :: views :: Прилегающий предоставляет скользящее окно n элементов в диапазоне. Его итератор обычно хранит n итераторы в базовом диапазоне. При реализации оператора этого итератора ++ я могу придумать два подхода:
[*] увеличение All : текущий подход, используемый основными реализациями (LibStdc ++, MSVC). Оператор ++ просто увеличивает все n хранимых базовых итераторов.// Simplified logic
for (auto & iter : current_window_iterators_) {
++iter;
}
Приращение последнего + shift : потенциально более эффективный подход. Поскольку следующее окно - это просто текущее окно, скользящее на одно, его итераторы (IT_2, IT_3, ..., IT_N, ++ IT_N) . Это может быть реализовано с помощью n-1 перемещения итератора (например, std :: shift_left ) и только one приращение базового итератора. Например, итератор для std :: views :: filter должен найти следующий элемент, который удовлетворяет предикату, который может быть дорогой. В таком трубопроводе, как источник | std :: Views :: Filter (...) | std :: views :: Прилегающий , подход «Приращение All» будет вызовать дорогостоящий приращение Filter 5 раз для каждого шага redcent_view итератор. Подход «Приращение последнего + сдвига» будет вызвать его только один раз. (Если Filter_View прикован в цепочке после Transform_view, я наблюдал, как время вызывания функции преобразования растет в геометрической прогрессии.) < /P>
По моему опыту, движения итератора почти всегда дешевы. Почему текущие стандартные реализации библиотеки используют подход «Приращение все», который кажется менее эффективным? Есть ли требование стандартного соответствия C ++, которые мне не хватает? Или это просто выбор реализации для простоты? < /P>
Benchmark < /h3>
код: < /p>
#include
#include
#include
#include
#include
#include
template
struct IterHelper
{
template
struct IterBase
{
using value_type = std::array;
using reference_type = std::array;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
std::array current;
IterBase(BaseIter it)
{
for (auto & iter : current)
{
iter = it;
++it;
}
}
auto operator*() const
{
return std::apply([](auto && ... it)
{
return std::array{ *it ...};
}, current);
}
bool operator==(IterBase const &) const = default;
D operator++(int)
{
auto & d = static_cast(*this);
auto temp = d;
++d;
return temp;
}
static auto make_range(BaseIter begin, std::ptrdiff_t len)
{
return std::ranges::subrange(D{ begin }, std::unreachable_sentinel) | std::views::take(len);
};
};
struct IterIncEach
: public IterBase
{
using Base = IterBase;
using Base::Base;
IterIncEach & operator++()
{
for (auto & it : Base::current)
++it;
return *this;
}
using Base::operator++;
};
struct IterShftInc
: public IterBase
{
using Base = IterBase;
using Base::Base;
IterShftInc & operator++()
{
auto & current = Base::current;
if constexpr (N >= 2)
{
for (size_t i = 0; i < N - 2; ++i)
current = std::move(current[i + 1]);
current[N - 2] = current[N - 1];
}
++(current[N - 1]);
return *this;
}
using Base::operator++;
};
};
#include
#include
#include
int main()
{
auto is_prime = [](int n)
{
for (int i = 2; i < n; ++i)
if (n % i == 0)
return false;
return true;
};
auto base_view = std::views::iota(100000) | std::views::filter(is_prime);
using BaseIter = std::ranges::iterator_t;
BaseIter iter0 = base_view.begin();
constexpr size_t Width = 3;
constexpr size_t Length = 100;
using Helper = IterHelper;
auto range_inc_each = Helper::IterIncEach::make_range(iter0, Length);
auto range_shft_inc = Helper::IterShftInc::make_range(iter0, Length);
using Result = std::vector;
Result res_inc_each; res_inc_each.reserve(Length);
Result res_shft_inc; res_shft_inc.reserve(Length);
using Clock = std::chrono::high_resolution_clock;
auto t0 = Clock::now();
for (auto i : range_inc_each)
{
res_inc_each.push_back(i);
}
auto t1 = Clock::now();
for (auto i : range_shft_inc)
{
res_shft_inc.push_back(i);
}
auto t2 = Clock::now();
std::print("IterIncEach: {}\n", t1 - t0);
std::print("IterShftInc: {}\n", t2 - t1);
std::print("equal: {}\n", res_inc_each == res_shft_inc);
}
< /code>
Результат: < /p>
IterIncEach: 73330162ns
IterShftInc: 24381067ns
equal: true
Подробнее здесь: https://stackoverflow.com/questions/797 ... tors-inste
Почему итераторы `std :: views :: смежные итераторы увеличивают все базовые итераторы вместо использования более эффекти ⇐ C++
Программы на C++. Форум разработчиков
1753686896
Anonymous
В C ++ 23, std :: views :: Прилегающий предоставляет скользящее окно n элементов в диапазоне. Его итератор обычно хранит n итераторы в базовом диапазоне. При реализации оператора этого итератора ++ я могу придумать два подхода:
[*] [b] увеличение All [/b]: текущий подход, используемый основными реализациями (LibStdc ++, MSVC). Оператор ++ просто увеличивает все n хранимых базовых итераторов.// Simplified logic
for (auto & iter : current_window_iterators_) {
++iter;
}
[b] Приращение последнего + shift [/b]: потенциально более эффективный подход. Поскольку следующее окно - это просто текущее окно, скользящее на одно, его итераторы (IT_2, IT_3, ..., IT_N, ++ IT_N) . Это может быть реализовано с помощью n-1 перемещения итератора (например, std :: shift_left ) и только one приращение базового итератора. Например, итератор для std :: views :: filter должен найти следующий элемент, который удовлетворяет предикату, который может быть дорогой. В таком трубопроводе, как источник | std :: Views :: Filter (...) | std :: views :: Прилегающий , подход «Приращение All» будет вызовать дорогостоящий приращение Filter 5 раз для каждого шага redcent_view итератор. Подход «Приращение последнего + сдвига» будет вызвать его только один раз. (Если Filter_View прикован в цепочке после Transform_view, я наблюдал, как время вызывания функции преобразования растет в геометрической прогрессии.) < /P>
По моему опыту, движения итератора почти всегда дешевы. Почему текущие стандартные реализации библиотеки используют подход «Приращение все», который кажется менее эффективным? Есть ли требование стандартного соответствия C ++, которые мне не хватает? Или это просто выбор реализации для простоты? < /P>
Benchmark < /h3>
код: < /p>
#include
#include
#include
#include
#include
#include
template
struct IterHelper
{
template
struct IterBase
{
using value_type = std::array;
using reference_type = std::array;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
std::array current;
IterBase(BaseIter it)
{
for (auto & iter : current)
{
iter = it;
++it;
}
}
auto operator*() const
{
return std::apply([](auto && ... it)
{
return std::array{ *it ...};
}, current);
}
bool operator==(IterBase const &) const = default;
D operator++(int)
{
auto & d = static_cast(*this);
auto temp = d;
++d;
return temp;
}
static auto make_range(BaseIter begin, std::ptrdiff_t len)
{
return std::ranges::subrange(D{ begin }, std::unreachable_sentinel) | std::views::take(len);
};
};
struct IterIncEach
: public IterBase
{
using Base = IterBase;
using Base::Base;
IterIncEach & operator++()
{
for (auto & it : Base::current)
++it;
return *this;
}
using Base::operator++;
};
struct IterShftInc
: public IterBase
{
using Base = IterBase;
using Base::Base;
IterShftInc & operator++()
{
auto & current = Base::current;
if constexpr (N >= 2)
{
for (size_t i = 0; i < N - 2; ++i)
current[i] = std::move(current[i + 1]);
current[N - 2] = current[N - 1];
}
++(current[N - 1]);
return *this;
}
using Base::operator++;
};
};
#include
#include
#include
int main()
{
auto is_prime = [](int n)
{
for (int i = 2; i < n; ++i)
if (n % i == 0)
return false;
return true;
};
auto base_view = std::views::iota(100000) | std::views::filter(is_prime);
using BaseIter = std::ranges::iterator_t;
BaseIter iter0 = base_view.begin();
constexpr size_t Width = 3;
constexpr size_t Length = 100;
using Helper = IterHelper;
auto range_inc_each = Helper::IterIncEach::make_range(iter0, Length);
auto range_shft_inc = Helper::IterShftInc::make_range(iter0, Length);
using Result = std::vector;
Result res_inc_each; res_inc_each.reserve(Length);
Result res_shft_inc; res_shft_inc.reserve(Length);
using Clock = std::chrono::high_resolution_clock;
auto t0 = Clock::now();
for (auto i : range_inc_each)
{
res_inc_each.push_back(i);
}
auto t1 = Clock::now();
for (auto i : range_shft_inc)
{
res_shft_inc.push_back(i);
}
auto t2 = Clock::now();
std::print("IterIncEach: {}\n", t1 - t0);
std::print("IterShftInc: {}\n", t2 - t1);
std::print("equal: {}\n", res_inc_each == res_shft_inc);
}
< /code>
Результат: < /p>
IterIncEach: 73330162ns
IterShftInc: 24381067ns
equal: true
Подробнее здесь: [url]https://stackoverflow.com/questions/79716126/why-do-stdviewsadjacent-iterators-increment-all-underlying-iterators-inste[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия