Только не бегите покупать их акции. Это надо было делать 3 года назад.
Хотя всё равно нельзя :(
Хотя всё равно нельзя :(
👍3
Я когда-то давно соптимизировал вот такое выражение
На днях пришел чел и убрал
Додумать до таких оптимизаций ни один ИИ сам не умеет.
Но искать глупые ошибки даже в низкоуровневом коде - очевидно да.
Читателям предлагается самим придумать эти оптимизации.
Ленивым читателям:
Смотреть сюда https://github.com/zakarumych/rapid-qoi/pull/12
(a * 3 + b * 5 + c * 7 + d * 11) & 63
До трех инструкций
mul
shr
and
На днях пришел чел и убрал
and.
А github copilot взял, да и нашел мелкую ошибку в коде чела.Додумать до таких оптимизаций ни один ИИ сам не умеет.
Но искать глупые ошибки даже в низкоуровневом коде - очевидно да.
Читателям предлагается самим придумать эти оптимизации.
Ленивым читателям:
🔥5👍1
Понял сегодня, что один поляк предсказал генеративные LLM целых 62 года назад.
Да, этоСтанислав Лем
Да, это
🔥8💯1
Кто-нибудь уже опробовал
"No Rest for the Wicked"?
Побегал пока бесплатная была, выглядит интересно, дизайн стильный.
Ко-оп добавили. Есть желающие пройти в коопе?
"No Rest for the Wicked"?
Побегал пока бесплатная была, выглядит интересно, дизайн стильный.
Ко-оп добавили. Есть желающие пройти в коопе?
Сам концепт "выглядеть как-то", это что-то из макро области.
Когда речь идет о единицах квантовых объектов, то фотоны поглащаются/излучаются случайным образом и строить какую-то картинку из этого не представляется возможным.
Лишь на больших масштабах выявляется сигнал из шума случайностей и появляется "выглядеть".
Когда речь идет о единицах квантовых объектов, то фотоны поглащаются/излучаются случайным образом и строить какую-то картинку из этого не представляется возможным.
Лишь на больших масштабах выявляется сигнал из шума случайностей и появляется "выглядеть".
❤4
Я два дня сражался с тем фактом, что в Rust нельзя просто взять и написать
почему? потому, оставили невозможным что бы дизайнить взаимодействие конста и трейтов в спокойствии еще несколько лет.
Если бы без
Если что
Пробовал сделать функцию не
До некоторой глубины действительно оптимизировалось.
В итоге пришел вот к такой форме "конст-функции-на-стейбле"
Это ужасно выглядит? Да.
Это гарантирует, что в результате компиляции на месте
trait Foo {
const fn bar(arg: Arg) -> Ret;
}почему? потому, оставили невозможным что бы дизайнить взаимодействие конста и трейтов в спокойствии еще несколько лет.
Если бы без
Arg - я бы просто сделал const BAR: Ret.Если что
const BAR<const ARG: Arg>; Тоже нельзя, но хотя бы в найтли можно.Пробовал сделать функцию не
const, но писать её, как если бы она была const. Надеялся, что соптимизируется.До некоторой глубины действительно оптимизировалось.
В итоге пришел вот к такой форме "конст-функции-на-стейбле"
trait Foo {
type Bar<const ARG: Arg>: RetType;
}
trait RetType {
const VALUE: Ret;
}
impl Foo for FooImpl {
type Bar<const ARG: Arg> = FooBar<ARG>;
}
struct FooBar<const ARG: Arg>;
impl RetType for FooBar<const ARG: Arg> {
const VALUE: Ret = {
// faked const fn body.
};
}Это ужасно выглядит? Да.
Это гарантирует, что в результате компиляции на месте
FooImpl::Bar::<ARG>::VALUE будет константа, а не вызов функции? Тоже да.❤6👍4🔥1
Я снова решил поупражняться в сериализаторском деле.
Я как-то давно писал библиотеку
Идея её проста - разделение ответственности. Тогда как в
Так же, если у вас есть данные для сериализации, но не в виде сериализуемого типа, вам обязательно нужно будет собрать их в сериализуемый тип.
Если там
Абсурд? Абсурд. Но ёжики продолжают жрать кактус.
Что даёт явная схема?
1. Много разных типов могут сериализовываться в одну явно указываемую схему. Результат "гарантировано" будет соответствовать схеме, а значит любой десерилизуемый тип, который поддерживает эту схему, можно получить из этих данных.
Так можно сериализовывать и десериализовывать
2. Сериализовывать типы, собственная структура которых является подмножеством схемы.
Например массив может писать свой размер при сериализации, если схема -
Структура может сериализовываться в определенный вариант enum-а, но все равно писать дискриминант.
Всё потому что схема диктует что писать, а сериализуемое значение только уточняет значение битов.
3. Десериализовывать типы, собственная структура которых является надмножеством схемы. Где
Повторяя пример с массивом, можно десериализовать схемы
Можно пропустить поля в структуре и не десериализовывать их вовсе. Если у схемы поля фиксированный размер, то даже его читать не придется.
Или можно отложить десериализацию куска данных на потом, если всё же понадобится.
Кроме всего и ядро и сгенерированный код на Rust полностью unsafe-free, а по скорости соперничает unsafe-heavy библиотеками, такими как rkyv. Новая цель - догнать
Всё это и многое другое уже есть в последней версии
Во-первых чтобы поддержать другие языки. У вас бэк с Rust и Python, а на фронте JS? Игра на Unreal (C++), а сервер на Rust? Alkahest поможет им общаться.
Кто пользовался protobuf, Flexbuffers и Flatbuffers? Alkahest по процессу сериализации ближе всех к Flatbuffers, но круче конечно, ведь есть дженерики :)
До сих пор схема писалась либо руками (на Rust), либо генерировалась процедурным макросом из объявления структуры или энама.
Сейчас я соорудил небольшой DSL, на котором можно описывать схемы.
Но я бы ни за что не просил программистов на Rust запускать генератор кода через build-script, поэтому генерация раста происходит в проценурном макросе вот так:
Генерируется целый модуль, в котором будут все схемы из файла.
Старый вариант с derive-макросом для схемы остаётся для быстрого plug'n'play использования.
Для С++ будет генерация кода, которую надо будет добавить в билдскрипты.
Python будет парсить функцией, а схемы возвращаться `dict`ом.
Как правильно делать для JS я еще разберусь :)
Я как-то давно писал библиотеку
alkahest для сериализации со схемой.Идея её проста - разделение ответственности. Тогда как в
serde (самой популярной библиотеке для сериализации) сериализуемый и десериализуемый тип диктует схему, то начинаются проблемки, когда это два разных типа - нет никакой гарантии, что схема их совпадёт.Так же, если у вас есть данные для сериализации, но не в виде сериализуемого типа, вам обязательно нужно будет собрать их в сериализуемый тип.
Если там
HashMap, а у вас данные в итераторе - придется делать Iterator::collect только лишь за тем что бы функция сериализатора вызвала HashMap::iter.Абсурд? Абсурд. Но ёжики продолжают жрать кактус.
Что даёт явная схема?
1. Много разных типов могут сериализовываться в одну явно указываемую схему. Результат "гарантировано" будет соответствовать схеме, а значит любой десерилизуемый тип, который поддерживает эту схему, можно получить из этих данных.
Так можно сериализовывать и десериализовывать
Vec, VecDeque и итераторы, ведь все они сооветствуют схеме List Слайсы только сериализовывать.2. Сериализовывать типы, собственная структура которых является подмножеством схемы.
Например массив может писать свой размер при сериализации, если схема -
List, а в схему Array<N> не нужно.Структура может сериализовываться в определенный вариант enum-а, но все равно писать дискриминант.
Всё потому что схема диктует что писать, а сериализуемое значение только уточняет значение битов.
3. Десериализовывать типы, собственная структура которых является надмножеством схемы. Где
/dev/null считается надмножество всего.Повторяя пример с массивом, можно десериализовать схемы
Array<N> в Vec, а <Vec as Deserialize<Array<N>>>::deserialize не будет пытаться искать размер в данных.Можно пропустить поля в структуре и не десериализовывать их вовсе. Если у схемы поля фиксированный размер, то даже его читать не придется.
Или можно отложить десериализацию куска данных на потом, если всё же понадобится.
Кроме всего и ядро и сгенерированный код на Rust полностью unsafe-free, а по скорости соперничает unsafe-heavy библиотеками, такими как rkyv. Новая цель - догнать
bitcodeВсё это и многое другое уже есть в последней версии
alkahest. Зачем же я опять за него взялся?Во-первых чтобы поддержать другие языки. У вас бэк с Rust и Python, а на фронте JS? Игра на Unreal (C++), а сервер на Rust? Alkahest поможет им общаться.
Кто пользовался protobuf, Flexbuffers и Flatbuffers? Alkahest по процессу сериализации ближе всех к Flatbuffers, но круче конечно, ведь есть дженерики :)
До сих пор схема писалась либо руками (на Rust), либо генерировалась процедурным макросом из объявления структуры или энама.
Сейчас я соорудил небольшой DSL, на котором можно описывать схемы.
Но я бы ни за что не просил программистов на Rust запускать генератор кода через build-script, поэтому генерация раста происходит в проценурном макросе вот так:
#[alkahest("schemas.alk")] // Путь до файла со схемами. Если не указано, то это "<modulename>.alk".
mod schemas {} // я бы предпочел mod schemas; но на стейбле нельзя. Макрос принимает обе формы.Генерируется целый модуль, в котором будут все схемы из файла.
Старый вариант с derive-макросом для схемы остаётся для быстрого plug'n'play использования.
Для С++ будет генерация кода, которую надо будет добавить в билдскрипты.
Python будет парсить функцией, а схемы возвращаться `dict`ом.
Как правильно делать для JS я еще разберусь :)
🔥5❤1
Во-вторых чтобы реализовать верифицируемую эволюцию схемы.
Схемы очень часто изменяются с выходом новых версий программы. Общающиеся программы обновляются не синхронно и надо как-то им уметь продолжать общение несмотря на то что у кого-то схема новее, у кого-то древнее. Так же сохраненные данные могут быть старой версии.
Для этого схемы должны обладать совместимостью. Совместимость бывает прямой и обратной, давайте рассмотрим оба случая.
Обратная совместимость означает, что данные сериализованные старой версией схемы могут быть десериализованны новой версией.
Прямая совместимость означает, что данные сериализованные с новой версией схемы могут быть десериализованны старой версией.
Как такое возможно? Десериализатор должен узнать какая версия схемы у данных, либо снаружи, либо из данных. А так же должна быть стратегия того, как конвертировать данные, например какое значение новым полям указать.
Это уже сразу несколько вариантов. Alkahest точно будет поддерживать вариант с указанием версии снаружи и указанием версии прямо в данных.
Но скорее всего не будет варианта с указанием в данных версии для субструктур, всё дерево схемы будет с одной версией.
С прямой совместимостью есть еще вариант без указания версии. Если новая версия строго шире старой, то десериализатор со старой схемой просто игнорирует хвост.
Тут помогает сериализация с указателем, потому что размер поля указателя фиксированный, так что схема может обладать прямой совместимостью и не влиять на схему, полем которой она является, если используется указатель.
То есть если было:
То старая формула
Что тут будет делать Alkahest? Проверять совместимость! Автор схемы указывает вид совместимости, а функция верификации убедится, что новая схема обладает указанной совместимостью со старой схемой.
Ультой будет проверка диффа кода на наличие несовместимых изменений схемы. И GitHub Action для запуска этой проверки в PR.
Схемы очень часто изменяются с выходом новых версий программы. Общающиеся программы обновляются не синхронно и надо как-то им уметь продолжать общение несмотря на то что у кого-то схема новее, у кого-то древнее. Так же сохраненные данные могут быть старой версии.
Для этого схемы должны обладать совместимостью. Совместимость бывает прямой и обратной, давайте рассмотрим оба случая.
Обратная совместимость означает, что данные сериализованные старой версией схемы могут быть десериализованны новой версией.
Прямая совместимость означает, что данные сериализованные с новой версией схемы могут быть десериализованны старой версией.
Как такое возможно? Десериализатор должен узнать какая версия схемы у данных, либо снаружи, либо из данных. А так же должна быть стратегия того, как конвертировать данные, например какое значение новым полям указать.
Это уже сразу несколько вариантов. Alkahest точно будет поддерживать вариант с указанием версии снаружи и указанием версии прямо в данных.
Но скорее всего не будет варианта с указанием в данных версии для субструктур, всё дерево схемы будет с одной версией.
С прямой совместимостью есть еще вариант без указания версии. Если новая версия строго шире старой, то десериализатор со старой схемой просто игнорирует хвост.
Тут помогает сериализация с указателем, потому что размер поля указателя фиксированный, так что схема может обладать прямой совместимостью и не влиять на схему, полем которой она является, если используется указатель.
То есть если было:
formula A = { ... }
formula B = { ... }
formula Foo = {
a: A,
b: B,
};
formula Bar = {
a: &A,
b: &B,
};То старая формула
Foo не будет совместимой с новой версией, если A расширилось, а Bar будет.Что тут будет делать Alkahest? Проверять совместимость! Автор схемы указывает вид совместимости, а функция верификации убедится, что новая схема обладает указанной совместимостью со старой схемой.
Ультой будет проверка диффа кода на наличие несовместимых изменений схемы. И GitHub Action для запуска этой проверки в PR.
👍1🔥1
Интересным образом оказывается, что не так уж сложно сериализовывать
Без специализации и special-casing-а.
Просто дискриминанты с uninhabited схемами не считаются.
А значит у
Option<!> в 0 байт.Без специализации и special-casing-а.
Просто дискриминанты с uninhabited схемами не считаются.
А значит у
Option<!> только 1 дискриминант None. Значит надо 0 байт на него, и на его тело тоже 0 байт.🤣2💯1👀1
Еще одно очевидное свойство
Его можно сериализовать в любую схему!
В самом деле, если мы сериализуем значение
На практике
А вот десериализовывать
Потому что эта схема не имеет представления в данных.
На практике
! типа и сериализации.Его можно сериализовать в любую схему!
В самом деле, если мы сериализуем значение
!, то как известно этот код недостижим. А значит не важно, какая там схема.На практике
! будет у варианта `enum`а, который невозможен. Значит сериализовываться будет всегда какой-то другой вариант или вообще не будет.А вот десериализовывать
! можно только из схемы !.Потому что эта схема не имеет представления в данных.
На практике
! будет у варианта схемы enum`а, которому дискриминант не назначен вовсе, а значит какие бы ни были данные, а функция десериализации ! не будет вызвана.Загадка про Rust
Что происходит с атрибутом
Что происходит с атрибутом
#[cold] над const функцией, когда её вызов вычисляется еще до LLVM?#[cold]
const fn mark_cold() {}
if condition {
mark_cold();
// Это холодный бранч или нет?
}
🤔6