Эффективность сплющивания и сбора ломтиков - PullRequest
2 голосов
/ 26 октября 2019

Если кто-то использует стандарт .flatten().collect::<Box<[T]>>() на Iterator<Item=&[T]> where T: Copy, делает ли он:

  • выполняет одно выделение;и
  • используйте memcpy, чтобы скопировать каждый элемент в место назначения

или это делает что-то менее эффективное?

1 Ответ

2 голосов
/ 26 октября 2019

Box<[T]> не реализует FromIterator<&T>, поэтому я предполагаю, что ваш действительный внутренний итератор - это то, что приводит к владению T s.

FromIterator<T> для Box<[T]> для пересылки в Vec<T>, который использует size_hint(), чтобы зарезервировать пространство для lower + 1 элементов, и перераспределяется по мере его роста (при необходимости перемещая элементы). Итак, вопрос в том, что Flatten<I> возвращает для size_hint?

Реализация Iterator::size_hint для Flatten<I> пересылает во внутреннюю структуру FlattenCompat<I>, которая являетсянемного сложнее, потому что он поддерживает двустороннюю итерацию, но в конечном итоге возвращает (0, None), если внешний итератор не был расширен или исчерпан .

Итак, ответ на ваш вопрос: он что-то делаетменее эффективным. А именно (если вы уже не вызывали next или next_back на итераторе хотя бы один раз), он создает пустой Vec<T> и постепенно увеличивает его в соответствии с любой стратегией роста, используемой Vec (которая не указана, но гарантируется документацией, что O(1) амортизируется push).

Это не является искусственным ограничением;это фундаментально для работы Flatten. Единственный способ предварительно рассчитать размер сплющенного итератора - это исчерпать внешний итератор и сложить все внутренние size_hint с. Это плохая идея, поскольку она не всегда работает (внутренние итераторы могут не возвращать полезных size_hint с), а также потому, что вам также нужно найти способ сохранить внутренние итераторы после исчерпания внешнего;не существует решения, которое было бы приемлемо для адаптера итератора общего назначения.

Если вы знаете что-то о своем конкретном итераторе, которое позволяет вам узнать, каким должен быть конечный размер, вы можете зарезервировать выделение самостоятельно, вызвав Vec::with_capacity и используйте Extend, чтобы заполнить его из flatten ed итератора, вместо использования collect.

...