Panzerschrek[CN]
> Имеет ли это какой-либо смысл?
Оптимизация пары (адрес массива + индекс), в горячих циклах может дать существенный прирост.
> Во-вторых: какой тип должен быть у разности указателей?
Заведи специальный, который внутри хранит разницу адресов, не деленную на sizeof(T).
> А может ну её, эту разность и она никому не нужна?
Лично мне в C++ не хватает разности (и соответствующей суммы) указателей разных типов.
Т. е. нужна типобезопасная замена reinterpret_cast хакам с offsetof:
struct S { float a; int b; float c; }; void test() { S s, *ps = &s; float *pc = &s.c; float S::*mp = pc - ps; // аналогов нет S *ps1 = pc - mp; // аналогов нет float *pc1 = ps + mp; // = &(ps->*mp) assert( ps1 == ps && pc1 == pc); }
// версия с одними скобками, и особым значком "<--" вместо пропечатки "=" fn u32_to_str; // function ... number to text. var.u32 x, // локальный параметр хикс создаётся с 1-го аргумента. // link r; // линк result_str, как любой масив. link.u8[ 64] r; // линк на внешний аргумент. // После такого указания, компилятор обязан выдавать ошибку, если // второй аргумент не опознался, как масив в 64 байта. [ var[ link.type] zero_char <-- 48; if x == 0; [ r[ 0] <-- zero_char; r[ 1] <-- 0; return; ] var.u32 dst <-- 0; var.u32 div <-- 1000000000; while div > x; [ div /= 10;] while div >= 1; [ var[ link.type] digit <-- x / div; r[ dst] <-- zero_char + digit; // 48 + 1 для пропечатки единицы x -= digit * div; div /= 10; dst += 1; ] r[ dst] <-- 0; ] // call: // var.u8[ 64] buf; u32_to_str[ 123, buf];
}:+()___ [Smile]
> разности (и соответствующей суммы) указателей разных типов
> нужна типобезопасная замена reinterpret_cast
Где тут типобезопасность?
Да и не вижу я проблем с reinterpret_cast-ами. Ну преобразовал в char* и посчитал разность, это вполне дозволено.
> Заведи специальный, который внутри хранит разницу адресов, не деленную на sizeof(T).
Дополнительная сущность в системе типов. Оно нам надо?
slatazan
В чём смысл переделки синтаксиса? Не уловил мысль.
Panzerschrek[CN]
> Ну преобразовал в char* и посчитал разность, это вполне дозволено.
А вот я не уверен, что по стандарту можно вычитать указатели на разные объекты.
Там, вроде, даже выход за границу массива в процессе промежуточных вычислений — UB.
> Дополнительная сущность в системе типов. Оно нам надо?
Решать тебе. На мой взгляд, без лишнего деления более оптимально, плюс есть возможность работать с невыровненными парами объектов:
struct Vertex { vec3 pos; int flags; }; void process_pos(vec3 *pos, ptrdiff<vec3> step, int n) { for( int i = 0; i < n; i++, pos += step) {...} } Vertex v[4]; process_pos( &v.pos, &v[1].pos - &v[0].pos, 4); process_pos( &v.pos, sizeof( Vertex), 4); // или даже так
}:+()___ [Smile]
> можно вычитать указатели на разные объекты.
Можно, если они получены в результате одной аллокации (стековой или через new).
> ptrdiff<vec3>
Ага, и ещё шаблонность. Нафиг надо, проще сделать тупо разницу в знаковом типе с размером указателя.
Ещё есть вопрос в том, надо ли делить разницу на sizeof(element_type). По факту оно не сильно дорого, т. к. деление на константу заменяется умножением. А если разница тупо сравнивается с нулём, то и этого делать не надо.
Panzerschrek[CN]
// В чём смысл "других значков"
Просто так. Вдруг тебе понравится :)
Реализовал таки сырые указатели.
Что это включает:
Что не реализовано, в сравнении с C++:
Я уже переписал на использование сырых указателей стандартную библиотеку, выкинул самописный контейнер raw_ptr_mut, который внутри был реализован через целое число. Местами от этого код даже немного упростился. Ещё я малость поменял преобразователь заголовочных файлов Си, поддержал проброс указателей из Си в указатели Ü.
Теперь я ещё на один шаг ближе к внедрению TBAA (type based alias analysis), т. к. теперь из кода выкинуты многочисленные int_to_ptr/ptr_to_int преобразования, которые могли ему мешать.
В процессе реализации сырых указателей опять ощутил масштаб языка. По ходу действия я много раз натыкался на то, что оказывается, надо ещё что-то поправить, чтобы нормально добавить новый класс типов - реализовать инициализаторы и функции копирования для сырых указателей, поддержать специализацию в шаблонах, не забыть о требовании полноты типа элемента при выполнении арифметики над указателями, не забыть о разнице между указателями на типы нулевого размера, не забыть кодирование типов указателей в именах символов, добавить поддержку указателей в отладочной информации и т. д.
Решил тут немного переделать тип void. Сейчас он очень поход на void из С++. Тип этот неполон, но разрешены неявные преобразования к нему.
Сейчас я его решил переделать. Цель - чтобы можно было спокойно присвоить переменной результат вызова void функции и что-то с этим значением сделать. Дополнительно думаю открутить неявные преобразования ссылок в void, ибо нефиг.
Что скажете на этот счёт? Здравые ли это идеи?
Panzerschrek[CN]
> присвоить переменной результат вызова void функции и что-то с этим значением
> сделать.
А для чего это может быть полезно? Я что-то сам не придумаю так навскидку.
Vlad2001_MFS
> А для чего это может быть полезно?
В шаблонном коде полезно, чтобы не городить разную логику там, где может быть void или не void.
Panzerschrek[CN]
> Что скажете на этот счёт? Здравые ли это идеи?
Если у тебя есть нормальная поддержка типов нулевого размера, то мастхев.
В C++, кстати, есть ограниченная поддержка сабжа:
void foo() {} void bar( ) { return foo( ); }
}:+()___ [Smile]
> нормальная поддержка типов нулевого размер
Есть такое. В языке есть пустые кортежи и структуры, которые имеют нулевой размер.
Panzerschrek[CN]
> В языке есть пустые кортежи и структуры, которые имеют нулевой размер.
И их можно делать полями структуры брать на эти поля указатель и ничего не ломается?
Или делать из них массив и итерирование не зависнет от того что указатель инкрементируется на ноль?
kipar
> И их можно делать полями структуры брать на эти поля указатель и ничего не ломается?
> Или делать из них массив и итерирование не зависнет от того что указатель инкрементируется на ноль?
Ничего не ломается. Брать указатель - это тупо выполнить инструкцию getelementptr. Этот указатель будет указывать куда-то, но читать по нему что-то будет нельзя (ибо размер нулевой).
С итерированием история следующая: я специально реализовал шаблонный класс random_access_range, чтобы он хранил указатель + размер, а не пару указателей на начало и конец. В таком варианте всё работает нормально, итераций выходит сколько надо.
Есть ещё разность указателей. Компилятор генерирует ошибку, если указываемый тип имеет нулевой размер.