Size: a a a

2022 January 06
Блог*
Помните scoped threads из crossbeam, которые позволяют спавнить не 'static функции (замыкания, которые захватывают что-то по ссылке)?

В std скоро(™) собираются такое добавить: <twitter:m_ou_se>
источник
2022 January 07
Блог*
#prog #cpp #abnormalprogramming

twitter.com/sehetw/status/1465726704979267586

Вообще это было переслано в <twitter:Affective C++>, но прикольно, что на C++ можно до некоторой степени сымитировать именованные прерывания цикла
источник
Блог*
twitter.com/the_aiju/status/1469615225208983560

Извините, но это просто АААААААААААААААААААААААААА
источник
2022 January 08
Блог*
#prog

Тонкости оптимизации на уровне процессорных команд от Данилы.

t.me/experimentalchill/139
Telegram
Experimental chill
На фоне анонсов Intel и AMD вспомнилась хорошая история:

PEXT (parallel extract) и PDEP (parallel deploy) являются инструкциями, которые появились в Intel Haswell и в наборе инструкций BMI2. Они очень полезны, так как переносят и распространяют биты в 64 битных числах склеиванием и расклеиванием соответственно:

PEXT: mask=0xff00fff0 src=0x12345678 dst=0x00012567
PDEP: mask=0xff00fff0 src=0x00012567 dst=0x12005670


Их применение достаточно часто можно оправдать. Скажем, можно использовать для того, чтобы быстрее парсить целые числа в протобуфах, где первый бит отвечает за то, последнее ли это число, а остальные 7 являются числовыми -- тем самым можно сделать pext с маской, которая склеит только биты с 1 по 7 у каждого байта, получив число. Такие числа называют varint, в 2000х годах это было хорошим компромиссом, так как они экономят место по сети/диску, если числа маленькие (что является очень частым кейсом).

Если сейчас поискать по кодовой базе протобуфа, то вы не увидите этих инструкций, казалось бы, почему…
источник
2022 January 09
Блог*
#prog #cpp #article

shared_ptr<T>: the (not always) atomic reference counted smart pointer

Статья о том, как shared_ptr может использовать не атомарные инкременты (и некоторые спекуляции на тему того, является ли это вообще безопасным)
источник
2022 January 11
Блог*
A lot of fonts show letter I and l very similar and it's wrong.

If you somewhere use any fonts, take care about they have different I and l especially where there is user input (like about yourself, post texts, etc)
источник
Блог*
#prog #meme
источник
Блог*
источник
2022 January 12
Блог*
#article

Статья (перевод) от основателя Signal с впечатлениями от так называемого web3.

TL;DR: реалии этих проектов противоречат декларируемым ценностям (главным образом децентрализации) и вообще катастрофически сломаны.
источник
Блог*
источник
Блог*
#itsec #article

A deep dive into an NSO zero-click iMessage exploit: Remote Code Execution

Подробная техническая статья о том, как именно работает 0-click exploit, позволяющий скомпрометировать устройство без каких-либо действий со стороны пользователя. Опять комбинация out of bounds {write, read} и парсера изображений вкупе с Тьюринговой трясиной одного экзотического формата изображений.
источник
2022 January 13
Блог*
Какой ваш любимый язык программирования и почему это Rust?
источник
Блог*
#prog #rust
источник
Блог*
В свежем Rust 1.58.0 наконец-то можно использовать переменные напрямую при форматировании строк:

let person = get_person();
// ...
println!("Hello, {person}!"); // captures the local `person`

Пока что это работает только с именами, а не произвольными выражениями, но всё равно приятно. Прощайте format!("{name}", name = name);!
источник
Блог*
Ещё из плющек:
— теперь *const T указатели можно дерефать в константных контекстах
— Теперь правила ансайзинга для дженерик структур немного проще[1]
— В copy{,_nonoverlapping} опять включили debug_assert'ы[2]
— реализация Clone для RSplit<T, P> больше не требует T: Clone
— Трейт Termiation теперь реализов для Result<Infallible, E>, позволяя писать fn main() -> Result<Infallible, ErrorType>, для програм которые не заканчиваются успешно через выход из main
— Стабилизировали File::options, замену FileOptions::new
— Стабилизировали {Option,Result}::unwrap_unchecked
— Стабилизировали многие методы Duration и MaybeUninit как const fn
— Компилятор теперь будет пытаться применять стабильные методы прежде, чем не стабильные. Это позволит избежать поломок при добавлении в std
методов, пересикающихся по именам с методами из сторонних трейтов.
rustdoc теперь показывает методы из всех Deref реализаций, рекурсивно (а не только из первой)

[1]: Новые правила позволяют такое:
struct A<T, U: ?Sized + 'static>(T, B<T, U>);
struct B<T, U: ?Sized>(T, U);

fn main() {
   let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
   // This previously did not work as the last field of `A` also mentions `T`,
   // as only `U` changes this is now allowed thanks to this feature.
   let _y: &A<[u32; 1], [u32]> = &x;
}

TL;DR: если последнее поле это структура, которая ансайзиться, то теперь и наружняя структура тоже ансайзиться.

А полные новые правила такие:
— the tail field depends on at least one type or const parameter not used in any other field
— the target struct can be created from the source by replacing only the parameters only found in the last struct field
— the tail field implements Unsize from source to target

[2]: Ранее они были отключены из-за того, что их нельзя выполнить в const fn

Полный список изменений: RELEASES.md#version-1580-2022-01-13
источник
Блог*
#prog #rust

Хозяйке на заметку

Как известно, если у типа в Rust есть несколько методов от разных трейтов с одними и теми же именами, то попытка вызвать один из них при помощи синтаксиса метода будет прервана компилятором с жалобой на неоднозначность имён, вынуждая прибегнуть к развёрнутому синтаксису вызова (Trait::method(&value, arg1, arg2)). Менее известен тот факт, что методы самого типа (inherent methods) перекрывают одноимённые методы трейтов, так что если одному имени отвечают метод типа и сколько угодно методов трейтов, то предпочтение всегда отдаётся методу самого типа и не вызывает неоднозначностей. Этим можно воспользоваться, чтобы иметь возможность в необобщённом контексте вызывать методы трейта, не импортируя сам трейт:

trait Trait {
   fn method(&mut self, arg: Arg);
}

struct Type {
   ...
}

impl Trait for Type {
   fn method(&mut self, arg: Arg) {
       ...
   }
}

impl Type {
   fn method(&mut self, arg: Arg) {
       Trait::method(self, arg)
   }
}

// где-то в другом месте, где в текущем пространстве имён
// есть Type, но нету Trait:

let mut value = Type::make(...);
value.method(arg);
источник
2022 January 14
Блог*
#prog #rust #моё

Допустим, нам нужно сделать на Rust бинарное дерево. Казалось бы, плёвое дело:

struct TreeNode<T> {
   value: T,
   left: Option<Box<Self>>,
   right: Option<Box<Self>>,
}

struct Tree<T> {
   root: Option<TreeNode<T>>,
}

Однако тут у нас по аллокации на каждый узел, от чего у нас страдает локальность данных и, как следствие, эффективность кеша (не говоря уже о стоимости аллокаций в рантайме). С другой стороны, у нас есть возможность делать дерево произвольной (насколько хватит оперативки, конечно же) высоты. А можем ли мы, отказавшись от произвольной высоты и задавая её предел наперёд, хранить вложенные узлы напрямую, а не через указатель? Как оказалось, да!

Но для начала немного о том, как мы будем задавать высоту. Так как решение на const generics потребует специализации и более продвинутой их обработки и потому абсолютно не реализуемо на стабильной версии, воспользуемся для задания высоты числами Пеано (да, я об этом уже писал):

struct Z;
struct S<T>(T);

Теперь немного подумаем о том, как это отобразить на древовидную структуру. Каждый узел дерева высотой N + 1 включает в себя узлы высотой N. Узел же дерева с высотой 0 не должен включать в себя данные вообще. Этого можно добиться, сопоставив Z тип с полями ненаселённого типа.

Кажется, что это изложение довольно легко перекладывается на код: определяем трейт с ассоциированным типом, который уменьшает число на единицу, реализуем его для S<T> с типом T, а для Z с типом never Infallible, параметризуем узел высотой Height и параметризуем вложенные узлы <Height as Decrement>::Output... К сожалению, это не работает: если определить узел таки образом, rustc не понимает, что рекурсия рано или поздно кончается, и жалуется на бесконечную вложенность типа без индирекции. Кажется, нам нужен другой подход.

С другой стороны, так уж сильно на его менять не придётся: вместо того, чтобы отображать каждое число на число на единицу меньше, вы воспользуемся структурной индукцией и будем отображать число непосредственно на тип узла:

struct Node<T, Next> {
   value: T,
   left: Next,
   right: Next,
}

Тут важно, что поля left и right имеют тип Next, а не Option<Next>, иначе мы не сможем сделать узел нулевой высоты ненаселённым типом. Собственно, вот как отображение выглядит для Z:

use std::convert::Infallible as Never;

trait Project<T> {
   type Projected;
}

impl<T> Project<T> for Z {
   type Projected = Node<T, Never>;
}

Итого узел нулевой высоты нельзя сконструировать, как мы и хотели. Лишь немногим сложнее выглядит отображение для S<N>:

impl<T, N> Project<T> for S<N>
where
   N: Project<T>,
{
   type Projected = Node<T, Option<N::Projected>>;
}

Так как мы не хотим оперировать узлами напрямую (хотя бы потому, что через них затруднительно наложить ограничение на высоту), сделаем обёртку — собственно параметризованное высотой дерево:

struct Tree<T, Height: Project<T>> {
   repr: Height::Projected,
}

Теперь реализуем парочку вспомогательных методов и попробуем сделать дерево высоты 2 (=S<S<Z>>):

let tree: Tree<i32, S<S<Z>>> = Node {
   value: 42,
   left: None,
   right: Some(Node {
       value: 42,
       left: None,
       right: None
   }),
}.into();

Что ж... Оно работает. И даже нормально печатается поле repr, если добавить #[derive(Debug)] на Node. Попробуем теперь поменять тип дерева на дерево с единичной высотой:

let tree: Tree<i32, S<Z>> = Node {
  ...

Компилятор ожидаемо жалуется:

error[E0271]: type mismatch resolving `<Z as Project<i32>>::Projected == Node<{integer}, Option<_>>`
  --> src/main.rs:181:7
   |
181 |     }.into();
   |       ^^^^ expected enum `Option`, found enum `Infallible`
   |
   = note: expected struct `Node<{integer}, Option<_>>`
              found struct `Node<i32, Infallible>`

Не слишком внятно, но цели статически ограничить высоту дерева мы  успешно достигли.

Как всегда, весь код в гисте. И на этот раз даже больше, чем в посте: добавлены методы для поиска по дереву (с допущением, что дерево является двоичным деревом поиска) и немного более приятная печать.

Оставайтесь на связи. 🤙
источник
Блог*
> Антон делает то, что я люблю в программировании больше всего — совершенно беcсмысленный, возведённый в абсолют бред, на который потрачено больше времени, чем стоило бы<...>

Ах, Вафель, ты был абсолютно прав.

Кстати, к него на канале уже 400 человечков! 👀🎉
источник
Блог*
источник
Блог*
#prog #rust #article

Why is my Rust build so slow? — офигенная статья от Амоса про ускорение компиляции большого проекта на Rust
источник