Size: a a a

2021 February 02
Блог*
Новое слово вам в словарик: "дыработка".
источник
Блог*
Что-то на канале в последнее время один сплошной шитпостинг. Надо уже что-то своё постить
источник
Блог*
#prog #rust

Поздравляю Вафлю! Лучшая кошкодевочка, однозначно.
источник
Блог*
Привет девочки!!

Мой PR в std (alloc) добавляющий Vec::extend_from_within наконец-то смерджили (tracking issue)!

tl;dr:
— Этот метод был предложен в RFC pr #2714
— Этот метод используется в разных крейтах и раньше его неправильные реализации приводили к UB
— Метод позволяет скопировать (склонировать) данные из вектора и добавить их в его же конец

let​ ​mut​ vec ​=​ ​vec!​[​0​, ​1​, ​2​, ​3​, ​4​];

vec.​extend_from_within​(​2​..);
​assert_eq!​(vec, [​0​, ​1​, ​2​, ​3​, ​4​, ​2​, ​3​, ​4​]);
источник
2021 February 03
Блог*
#prog #c #cpp #article

C-Reduce (GitHub) — C-Reduce is a tool that takes a large C, C++, or OpenCL file that has a property of interest (such as triggering a compiler bug) and automatically produces a much smaller C/C++ file that has the same property. It is intended for use by people who discover and report bugs in compilers and other tools that process source code.

В силу того, что принципиальный алгоритм для сокращения тестов, вопреки названию, не привязан к конкретному языку, на практике с успехом применяется и для сокращения тест-кейсов на других ЯП.

Также имеется статья в двух частях (первая, вторая) от создателя о дизайне C-Reduce (в частности, о том, как там можно применить многозадачность) и о том, как он работает на практике.
источник
Блог*
dereference_pointer_there
#prog #c #cpp #article

C-Reduce (GitHub) — C-Reduce is a tool that takes a large C, C++, or OpenCL file that has a property of interest (such as triggering a compiler bug) and automatically produces a much smaller C/C++ file that has the same property. It is intended for use by people who discover and report bugs in compilers and other tools that process source code.

В силу того, что принципиальный алгоритм для сокращения тестов, вопреки названию, не привязан к конкретному языку, на практике с успехом применяется и для сокращения тест-кейсов на других ЯП.

Также имеется статья в двух частях (первая, вторая) от создателя о дизайне C-Reduce (в частности, о том, как там можно применить многозадачность) и о том, как он работает на практике.
#prog #article

Данная статья рассказывает о фреймворке Perses для сокращения тестовых программ, который оперирует над вариантом контекстно-свободных грамматик, и за счёт этого:
1) Генерирует лишь синтаксически валидные программы, за счёт чего не теряет время на отбрасывание заведомо некорректных программ.
2) Позволяет проводить более продвинутые изменения кода, чем те, на которые способны более простые (Hierarchical) Delta Debugging (они также определяются в самой статье, так что не переживайте, если этот термин вам ни о чём не говорит).
3) Не привязан к конкретному языку (авторы смогли успешно применить его как для программ на C, так и для программ на Java).

Разумеется, помимо прочих вариантов авторы сравнили свой фреймворк и с C-Reduce. В смысле эффективности сжатия тестовых кейсов C-Reduce работает более эффективно за счёт большего количества C/C++-специфичных эвристик, но Perses тратит меньше времени на минимизацию и делает меньше тестовых запусков. Как итог, авторы предлагают на практике сначала запускать свой фреймворк, а потом уже допиливать при помощи C-Reduce
источник
Блог*
источник
Блог*
источник
2021 February 04
Блог*
источник
2021 February 05
Блог*
#prog #rust #article

Статья о программе для решения конкретной прикладной задачи: перевода списка контактов из PDF в форму, которую понимает телефон.
источник
Блог*
#prog #rust #моё

В Go есть такая фича, как iota. Это магический идентификатор, который можно использовать в блоке констант и который автоматически заменяется на порядковый номер в блоке констант. Наглядный пример:

package main

import (
 "fmt"
)

const (
 a = 0
 b = 1 << iota

 _
 // Oh hi Mark
 c
)

const (
 d = iota
)

func main() {
 fmt.Println(a)
 fmt.Println(b)
 fmt.Println(c)
 fmt.Println(d)
}

Вывод:

0
2
8
0

Данный пример демонстрирует, что:

* iota автоматически становится числом, соответствующим номеру непустой строки без комментариев
*  выражение для константы можно опустить, в этом случае оно становится (символически) идентичным последнему непустому выражению
* константу можно явно пропустить, в этом случае iota всё равно будет инкрементирована
* счётчик iota действует только в рамках одного блока деклараций констант, в следующем блоке он сбрасывается

На практике эта фича может быть полезна для определения битовых флагов:

const (
       FLAG_A = 1 << iota
       FLAG_B
       FLAG_C
       FLAG_D
)

Возможность пропустить константу позволяет удалить битовый флаг, не меняя значения остальных флагов.

Сегодня я сделаю на Rust макрос, который, насколько возможно, воспроизводит это поведение.

Прежде чем я приступлю к реализации, хочу отметить, что добиться в полной мере той же эргономики, что и на Go, несколько проблематично, поскольку в Rust декларативные макросы (а я собираюсь ограничиться именно ими) имеют гигиену и потому не могут генерировать новые идентификаторы, доступные извне макроса, а могут лишь использовать те, что уже имеются. Это можно решить, вручную выискивая iota в выражениях — это путь сильных, точнее, путь Толяна, поскольку в этом случае требуется вручную делать рекурсивный спуск внутрь выражений со скобками. Я же пойду по пути наименьшего сопротивления и обязую пользователя макроса предоставить идентификатор, который будет использован в качестве iota.

Давайте немного подумаем о том, как же решить задачу инкрементации. В силу того, что декларативные макросы можно считать некоей убогой разновидностью функционального программирования, воспользуемся подходами из ФП. Вместо того, чтобы сразу сгенерировать всю числовую последовательность, мы будем рекурсивно обрабатывать список деклараций, поддерживая текущее значение iota, и после генерации очередной константы вызывать макрос на остатке входа, передав инкрементированное значение iota.

Ещё один вопрос — как поддержать возможность опустить выражение для константы. Получается, что, помимо текущего значения iota, нам также нужно хранить выражение для константы. Оно передаётся дальше при рекурсивном вызове, при этом оно либо замещается текущим, если оно есть, либо используется и передаётся дальше без изменений.

Разумеется, рекурсию нужно с чего-то начать. Базой индукции послужит инициализация iota нулевым значением, а выражение для константы можно инициализировать самой iota:

macro_rules! iota_consts {
   (
       $iota:ident: $($tt:tt)*
       //^             ^^весь остальной вход
       //\- идентификатор для iota
   ) => {
       iota_consts!(
           $iota(0, $iota): $($tt)*
       );
   };
  ...

Теперь немного подумаем о том, как распознать константу. Обязательные элементы — это ключевое слово const, имя, двоеточие, за которым следует тип. Также, вообще говоря, требуется знак равно, за которым следует выражение для константы, оканчивающуюся точкой с запятой, но в нашем синтаксисе они опциональны, так что их надо обрабатывать отдельно. Также, помимо обязательных элементов, у константы могут быть различные атрибуты и модификатор видимости. С учётом всего сказанного синтаксис для захвата необходимых составляющих константы выглядит следующим образом:

$(#[$attr:meta])*
$vis:vis
const $name:ident : $ty:ty
источник
Блог*
А теперь подумаем о том, как добавить определение константы. У нас есть имя, тип, и необходимые атрибуты, а также выражение для инициализации. Единственный недостающий ингредиент — это iota (ну или как там это выражение назвал пользователь). Вместо того, чтобы вручную сканировать выражению и заменять iota руками, мы просто предоставим его определение и сделаем его видимым в выражении. Иными словами, мы заведём отдельную константу с именем $iota. При этом надо иметь в виду две вещи. Во-первых, имя, данное пользователем, почти наверняка не написано в SCREAMING_SNAKE_CASE, которым обычно пишут имена констант. Во-вторых, это имя вполне может быть не использовано внутри выражения для константы. Для того, чтобы не вызывать предупреждений компилятора, мы заглушим их при помощи #[allow(dead_code, non_upper_case_globals)].

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

(
   $iota:ident($iota_value:expr, $prev_expr:expr):

   $(#[$attr:meta])*
   $vis:vis
   const $name:ident : $ty:ty; //нет выражения

   $($tt:tt)*
) => {
   $(#[$attr])*
   $vis
   const $name: $ty = {
       #[allow(dead_code, non_upper_case_globals)]
       const $iota: $ty = $iota_value;
       $prev_expr //переиспользуем предыдущее выражение
   };
   iota_consts!(
       //    vv--- инкрементируем передаваемое значение
       $iota($iota_value + 1, $prev_expr):
       //                     ^^- значение передаём без изменений
       $($tt)*
   );
};


Случай с наличием выражения для константы отличается не сильно:

(
   $iota:ident($iota_value:expr, $_prev_expr:expr):

   $(#[$attr:meta])*
   $vis:vis
   const $name:ident : $ty:ty = $const_value:expr;

   $($tt:tt)*
) => {
   $(#[$attr])*
   $vis
   const $name: $ty = {
       #[allow(dead_code, non_upper_case_globals)]
       const $iota: $ty = $iota_value;
       $const_value //используем текущее определение
   };
   iota_consts!(
       //                     vv- и передаём его дальше
       $iota($iota_value + 1, $const_value):
       $($tt)*
   );
};


Ещё одна фича, которую надо поддержать — это пропуск константы вообще. На самом деле она даже проще предыдущих:

(
   $iota:ident($iota_value:expr, $prev_expr:expr):

   _; //ничего, совсем ничего! Намеренно игнорируем

   $($tt:tt)*
) => {
   iota_consts!(
       //     vv- но обязательно инкрементируем
       $iota($iota_value + 1, $prev_expr):
       $($tt)*
   );
};


Ну и, как у любой рекурсии, у макроса должно быть условие завершения. В нашем случае им является пустой вход для обработки:

(
   $_iota:ident($_iota_value:expr, $_prev_expr:expr):
) => {};


В принципе, на это всё. Ввиду наличия вывода типа выражение для $iota само корректно типизируется, поэтому $iota получается эффективно безтиповым значением, как мы и хотели.

...Хотя нет, не всё. Ничто не мешает нам при помощи аналогичного макроса объявлять статические переменные, в том числе и мутабельные. К сожалению, я не нашёл способа избежать дупликации кода, не наталкиваясь на ограничения макросов, поэтому я просто тупо накопипастил ветки и поменял в нужных местах const на static и static mut соответственно.

Проверим теперь, как оно работает:

iota_consts!(iota:
   const FOO: u32 = 1 << iota;    // iota = 0, FOO = 1
   static BAR: i32;               // iota = 1, BAR = 2
   _;                             // iota = 2
   #[allow(dead_code)]
   static mut BAZ: i8 = iota + 2; // iota = 3, BAZ = 5
   const QUX: i16;                // iota = 4, QUX = 6
);

macro_rules! print_consts {
   ($($name:ident),*) => {
       $(println!("{} = {}", stringify!($name), $name);)*
   };
}

fn main() {
   print_consts! {
       FOO,
       BAR,
       /* BAZ */
       QUX
   };
}


Эта программа выводит:

FOO = 1
BAR = 2
QUX = 6


, как и ожидалось. Более того, ввиду аннотации #[allow(dead_code)] на BAZ компилятор не жалуется на неиспользованное определение. Также, очевидно, макрос позволяет определять константы разных типов.
источник
Блог*
Есть недостатки у нашего решения? Безусловно. Вот они в произвольном порядке:

* Как я уже говорил, идентификатор для iota приходится давать самому. Неприятно, но не смертельно.
* const повторяется для каждого определения. Если убрать возможность генерировать static (mut)?, то можно облегчить синтаксис, убрав эти ключевые слова.
* В Go можно объявить больше одной константы в одной строке, при это значение iota в выражениях для них будет одинаково. Мой макрос такого не умеет. Пока что неясно ни то, как это мешается на практике, ни то, как это поддержать.
* В Go iota можно также использовать в выражениях с дробными числами. Вот это уже более существенный недостаток, но его, в принципе, можно обойти кастами по месту.
* Ошибки в вычислениях показываются не там, где надо, и это совсем нехорошо. Поясню на примере:

iota_consts!(iota:
   const A: u8 = iota + u8::MAX;
   const B: u8;
);

Этот код вызывает следующую ошибку компиляции:

error: any use of this value will cause an error
  --> src/lib.rs:189:19
   |
24  | /         $vis
25  | |         const $name: $ty = {
26  | |             #[allow(dead_code, non_upper_case_globals)]
27  | |             const $iota: $ty = $iota_value;
28  | |             $prev_expr
29  | |         };
   | |__________-
...
189 |       const A: u8 = iota + u8::MAX;
   |                     ^^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow
   |
   = note: `#[deny(const_err)]` on by default

Как видите, не смотря на то, что ошибка произошла при вычислении B, компилятор указывает на выражение для`A`. В принципе, понятно, откуда это берётся: токены парсятся с исходными спанами, которые не меняются при преобразованиях макроса. К сожалению, это фундаментальное ограничение декларативных макросов, и я не вижу способа решить эту проблему.

Как всегда, весь код в гисте.
источник
Блог*
dereference_pointer_there
#prog #rust #моё

В Go есть такая фича, как iota. Это магический идентификатор, который можно использовать в блоке констант и который автоматически заменяется на порядковый номер в блоке констант. Наглядный пример:

package main

import (
 "fmt"
)

const (
 a = 0
 b = 1 << iota

 _
 // Oh hi Mark
 c
)

const (
 d = iota
)

func main() {
 fmt.Println(a)
 fmt.Println(b)
 fmt.Println(c)
 fmt.Println(d)
}

Вывод:

0
2
8
0

Данный пример демонстрирует, что:

* iota автоматически становится числом, соответствующим номеру непустой строки без комментариев
*  выражение для константы можно опустить, в этом случае оно становится (символически) идентичным последнему непустому выражению
* константу можно явно пропустить, в этом случае iota всё равно будет инкрементирована
* счётчик iota действует только в рамках одного блока деклараций констант, в следующем блоке он сбрасывается

На практике эта фича может быть полезна для определения битовых флагов:

const (
       FLAG_A = 1 << iota
       FLAG_B
       FLAG_C
       FLAG_D
)

Возможность пропустить константу позволяет удалить битовый флаг, не меняя значения остальных флагов.

Сегодня я сделаю на Rust макрос, который, насколько возможно, воспроизводит это поведение.

Прежде чем я приступлю к реализации, хочу отметить, что добиться в полной мере той же эргономики, что и на Go, несколько проблематично, поскольку в Rust декларативные макросы (а я собираюсь ограничиться именно ими) имеют гигиену и потому не могут генерировать новые идентификаторы, доступные извне макроса, а могут лишь использовать те, что уже имеются. Это можно решить, вручную выискивая iota в выражениях — это путь сильных, точнее, путь Толяна, поскольку в этом случае требуется вручную делать рекурсивный спуск внутрь выражений со скобками. Я же пойду по пути наименьшего сопротивления и обязую пользователя макроса предоставить идентификатор, который будет использован в качестве iota.

Давайте немного подумаем о том, как же решить задачу инкрементации. В силу того, что декларативные макросы можно считать некоей убогой разновидностью функционального программирования, воспользуемся подходами из ФП. Вместо того, чтобы сразу сгенерировать всю числовую последовательность, мы будем рекурсивно обрабатывать список деклараций, поддерживая текущее значение iota, и после генерации очередной константы вызывать макрос на остатке входа, передав инкрементированное значение iota.

Ещё один вопрос — как поддержать возможность опустить выражение для константы. Получается, что, помимо текущего значения iota, нам также нужно хранить выражение для константы. Оно передаётся дальше при рекурсивном вызове, при этом оно либо замещается текущим, если оно есть, либо используется и передаётся дальше без изменений.

Разумеется, рекурсию нужно с чего-то начать. Базой индукции послужит инициализация iota нулевым значением, а выражение для константы можно инициализировать самой iota:

macro_rules! iota_consts {
   (
       $iota:ident: $($tt:tt)*
       //^             ^^весь остальной вход
       //\- идентификатор для iota
   ) => {
       iota_consts!(
           $iota(0, $iota): $($tt)*
       );
   };
  ...

Теперь немного подумаем о том, как распознать константу. Обязательные элементы — это ключевое слово const, имя, двоеточие, за которым следует тип. Также, вообще говоря, требуется знак равно, за которым следует выражение для константы, оканчивающуюся точкой с запятой, но в нашем синтаксисе они опциональны, так что их надо обрабатывать отдельно. Также, помимо обязательных элементов, у константы могут быть различные атрибуты и модификатор видимости. С учётом всего сказанного синтаксис для захвата необходимых составляющих константы выглядит следующим образом:

$(#[$attr:meta])*
$vis:vis
const $name:ident : $ty:ty
Вот я наврал, а Вафель меня поправил, на константы гигиена не распространяется: https://t.me/ihatereality/1878

Короче, он опять умница, няша и кошкодевочка
Telegram
Мне не нравится реальность
Антон как обычно написал интересный пост, на этот раз про симуляцию iota из Go в Rust при помощи макросов (прочитайте его прежде, чем этот пост).

Однако в посте есть небольшая ошибка:

Хочу отметить, что добиться в полной мере той же эргономики, что и на Go, несколько проблематично, поскольку в Rust декларативные макросы [...] имеют гигиену и потому не могут генерировать новые идентификаторы, доступные извне макроса, а могут лишь использовать те что уже имеются.

Это правда, но не в полной мере. В растовых макросах действительно есть гигиена, но не для всего, например — не для констант. Это значит, что мы можем просто заменить $iota на iota (или любой идентификатор по вкусу) и это продолжит работать:

iota_consts! {
   // Явно передавать идентификатор не нужно
   const FOO: u32 = 1 << iota;    // iota = 0, FOO = 1
   const BAR: i32;                // iota = 1, BAR = 2
   _;                             // iota = 2
   const BAZ: i8 = iota + 2;      // iota = 3, BAZ = 5
   const QUX: i16;                //…
источник
2021 February 06
Блог*
#prog

Коллекция туториалов в духе "Build your own X"
источник
Блог*
#prog #gamedev
источник
Блог*
Townscaper — это градостроительная песочница, в которой игра сама выбирает блоки и автоматически встраивает их в окружение. Проект создан на Unity.

Геймдизайнер Оскар Стальберг рассказал, какие алгоритмы он использовал, чтобы добиться столь продуманной процедурной генерации.

Читать подробнее
источник
Блог*
dereference_pointer_there
Townscaper — это градостроительная песочница, в которой игра сама выбирает блоки и автоматически встраивает их в окружение. Проект создан на Unity.

Геймдизайнер Оскар Стальберг рассказал, какие алгоритмы он использовал, чтобы добиться столь продуманной процедурной генерации.

Читать подробнее
#prog #article

В игре активно используется алгоритм wave function collapse, который неплохо описан, например, в этой (перевод) статье и который, не смотря на объяснения, для меня до сих пор выглядит как чудо.
источник
Блог*
dereference_pointer_there
#prog #article

В игре активно используется алгоритм wave function collapse, который неплохо описан, например, в этой (перевод) статье и который, не смотря на объяснения, для меня до сих пор выглядит как чудо.
#prog #video

Серьёзно, посмотрите, например, вот это видео (лучше на 2x), это же восхитительно
источник
2021 February 07
Блог*
источник