мне не нравится реальность
507 subscribers
1.34K photos
57 videos
56 files
1.02K links
Мне не нравится реальность
N.B. waffle is unhinged

- кормить назад: @meowaffle
- кормить вперёд: github.com/sponsors/WaffleLapkin
- чят: https://xn--r1a.website/+5Dtuan4dVE5kYTcy
- блог: blog.ihatereality.space
Download Telegram
мне не нравится реальность
Вчера я провёл стрим, где начал писать двухсторонюю хэшмапу. Т.е. если в обычной HashMap отношение K -> V, то в BiHashMap отношение K <-> K'. ‍ Всё пошло не так, как бы хотелось (я это ожидал и поэтому не публиковал тут ссылку на стрим), но в итоге я смог…
TL;DR того, что случилось за 3 часа стрима:
— Кратко рассказал о том, что было на предыдущем стриме
— Написал небольшой типчик Mrc<_>, который по сути немного-более-безопасный указатель
— Переписал крейт с использования StaticRc, на Mrc
— Попытался написать {l,r}get_mut, понял что для BiHashMap такие методы не имеют смысла, разочаровался в жизни и впал в уныние
— Написал метод lreplace
— Неудачно попытался добавить проверки корнер кейсов в insert
— Долго пытался исправить проверки и избавиться от UB
— Придумал как правильно и просто написать проверки корнер кейсов в insert (оказалось почти совсем просто)

Итоговая реализация insert греет мне душу :)
как же хочется FulfillmentError
*не может выбрать аватарку для менеджера паролей*
В std добавили (PR смерджен 2 часа назад, будет в следующем найтли) pin! макрос!

tl;dr он позволяет делать так:
let foo: Pin<&mut PhantomPinned> = pin!(PhantomPinned);
stuff(foo);

Он работает аналогично tokio::pin! или futures::pin_mut! — припинивает значение к стеку, не давая ему больше двигаться. Но, в отличии от этих макросов является выражением. pin! из tokio и futures работают примерно так, tokio::pin!(stuff); разворячивается в

let mut stuff = stuff; // (1)
let stuff = unsafe { // (2)
Pin::new_unchecked(&mut stuff); // (3)
}

1. Проверяет что код владеет значением
2. Переменная "затеняется" в следствии чего к оригинальной переменной больше нет доступа и двигать оригинальное значение нельзя
3. Поскольку двигать значение будет нельзя, то можно спокойно создавать Pin

Этот хак работает, но он не очень удобен, т.к. pin!() получается отдельным стейтментом, а не выражением.

pin! из std использует другой хак, а конкретно правила по которым работают tmp-значения при создании структур через литерал. std::pin! разворачивается в

Pin::<&mut _> { pointer: &mut { stuff } }

Но как так? Ведь это же просто создания структуры Pin, как этот код может гарантировать, что stuff не будет двигаться в памяти, менять адрес, инвалидировать ссылки на себя? Давайте разберём по порядку.

1. { stuff } — это block expression, последнее выражение в блоке "возвращается" из него. это проверка на то, что код владеет stuff аналогичная пункту (1) из tokio/futures pin!. Это же и создаёт анонимную tmp-переменную которая гарантирует (своей анонимностью) что значение не будет двигаться.
2. ::<&mut _> говорит что Pin будет параметризован ссылкой на что-то, это не особо важно, но в макросах полезно быть как можно более точными, чтобы потом что-нибудь внезапно не сломалось
3. Pin { pointer: &mut ... } это самая интересная часть, которую не могли повторить макросы из futures/tokio, сейчас объясню почему

Когда вызываются функции, tmp переменные привязываются к вызову, т.е. f(&{ a }) превращается в
{
let tmp = a;
f(&tmp)
} // tmp умирает здесь
Соответственно таким образом нельзя вызвать функции, которые возвращают эту ссылку и потом эту ссылку использовать — tmp на который тут ссылаются к тому моменту уже умрёт.

Соответственно tokio/futures не могли у себя сделать Pin::<&mut _>::new_unchecked(&mut { stuff })let a = pin!(stuff) бы просто не работало т.к. пыталось бы вернуть ссылку на tmp, который уже умер.

Но при создании структур правила другие, Struct { field: &{ a } } превращается в
let tmp = a;
Struct { field: &tmp }
в таком случае tmp может жить гораздо дольше!

Поэтому то, что стандартная библиотека имеет доступ к приватному полю (как этот доступ работает в макросах это отдельная история) позволяет ей реализовать более удобное API, позволяющее делать вещи вроде

let stuff = pin!(expr);

Которое потом разворачивается в что-то на подобии

let mut tmp = expr;
let stuff = Pin { pointer: &mut tmp };

(и все счастливы)

P.S. особо любознательным советую прочитать вот этот огромный комментарий из реализации макроса
А вы тоже сидите грустные и уставшие, а потом такие
YOU'RE DEAD, ALREADY, DEAD, DEAD, ALREADY-READY
DEAD, ALREADY, DEAD, DEAD, ALREADY-READY
DEAD, ALREADY, DEAD, DEAD, ALREADY-READY
DEAD, ALREADY, deeeeaaaad

и сразу всё нипочём и сразу прыгать хочется?
cursed-fact-of-the-day: бинарный поиск по массиву из 2^20 элементов примерно на 20% медленнее, чем бинарный поиск по массиву из 2^20 + 123 элементов.

Причина: https://en.algorithmica.org/hpc/cpu-cache/associativity/

Источник: twitter@sergey_slotin
так грустно, что зима скоро закончится
Кстати на счёт стримов %)

Через пол часа, в ~18:00 @ twitch.tv/wafflelapkin я буду стримить Ring of Pain. Не знаю как нормально описать, но это игра, рогалик, там есть штуки.

На прошлом стриме я первый раз открыл игру и случайно прошёл её (забег длился всего 3 часа 13 минут), посмотрим что из себя представляет medium сложность хд
мне не нравится реальность
Кстати на счёт стримов %) Через пол часа, в ~18:00 @ twitch.tv/wafflelapkin я буду стримить Ring of Pain. Не знаю как нормально описать, но это игра, рогалик, там есть штуки. На прошлом стриме я первый раз открыл игру и случайно прошёл её (забег длился всего…
Вчера я в итоге прошёл игру только один раз (зато на другую концовку и всего за полтора часа!). Большинство попыток кончились ничем.

Мне всё ещё интересно что игра может ещё показать, так что давайте сегодня повторим стрим, в то же время, 18:00 (MSK/UTC+3) @ twitch.tv/wafflelapkin
А никто не знает, где можно иммутабельно сохранить фотку?

Хочу в коммит добавить ссылку на фотографию, но не хочу её добавлять в сам репозиторий.
Какой же кайф не тащить ноут с собой
Я вы читаете слово "передохни" как передохни или как передохни