- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
static inline void set0b (const uint8_t at, uint64_t bm[static 4])
{
bm[at / 64] &= ~(1ULL << (at % 64));
}
static inline void set1b (const uint8_t at, uint64_t bm[static 4])
{
bm[at / 64] |= 1ULL << (at % 64);
}
static inline void inv_b (const uint8_t at, uint64_t bm[static 4])
{
bm[at / 64] ^= 1ULL << (at % 64);
}
static inline uint8_t find_empt_pos (const uint64_t bm[static 4])
{
if (bm[0] != UINT64_MAX)
{
return __builtin_ctzll(~bm[0]) + 64 * 0; // __builtin_ctzll - https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
}
if (bm[1] != UINT64_MAX)
{
return __builtin_ctzll(~bm[1]) + 64 * 1;
}
if (bm[2] != UINT64_MAX)
{
return __builtin_ctzll(~bm[2]) + 64 * 2;
}
if (bm[3] != UINT64_MAX)
{
return __builtin_ctzll(~bm[3]) + 64 * 3;
}
fprintf(stderr, "ERROR! No empty space!\n");
exit (-1);
}
static inline uint8_t allocate_ll (uint64_t bm[static 4])
{
uint8_t tmp = find_empt_pos (bm);
set1b (tmp, bm);
return tmp;
}
static inline void inject(const uint8_t prev_p, const uint8_t next_p, const uint8_t at, struct ll_data a[static 256])
{
a[next_p].ll.prev = at;
a[prev_p].ll.next = at;
a[at].ll.prev = prev_p;
a[at].ll.next = next_p;
}
static inline void remove_betw(const uint8_t prev_p, const uint8_t next_p, struct ll_data a[static 256])
{
a[prev_p].ll.next = next_p;
a[next_p].ll.prev = prev_p;
}
static inline void remove_at(const uint8_t at, struct ll_data a[static 256], uint64_t bm[static 4])
{
uint8_t prev_t = a[at].ll.prev;
uint8_t next_t = a[at].ll.next;
set0b (at, bm);
a[at].ll.prev = next_t;
a[at].ll.next = prev_t;
}
void add_elem_next (struct ll_all *a, const uint8_t elm, const int value)
{
uint8_t pos = allocate_ll (a->bm);
inject(elm, a->arr[elm].ll.next, pos, a->arr);
set_elm (pos, value, a->arr);
}
void add_elem_prev (struct ll_all *a, const uint8_t elm, const int value)
{
uint8_t pos = allocate_ll (a->bm);
inject(a->arr[elm].ll.prev, elm, pos, a->arr);
a->arr[pos].data = value;
}
void rem_elem_next (struct ll_all *a, const uint8_t elm)
{
set0b (a->arr[elm].ll.next, a->bm);
remove_betw (elm, a->arr[a->arr[elm].ll.next].ll.next, a->arr);
}
void rem_elem_prev (struct ll_all *a, const uint8_t elm)
{
set0b (a->arr[elm].ll.next, a->bm);
remove_betw (a->arr[a->arr[elm].ll.prev].ll.prev, elm, a->arr);
}
это че за такой загадочный `static`?
Array declarators as function arguments now have a meaningful difference from pointer declarators: you can put in type qualifiers. Of particular interest is the very odd optimizer hint of giving an array declarator the static type modifier. Given this declaration: int foo(int a[static 10]);
It is undefined behavior to call foo() with a pointer that doesn't point to at least 10 objects of type int. This is an optimizer hint. All you're doing is promising the compiler that the argument passed to the function will be at least that large; some machines might use this for loop unrolling.
The information provided by static in parameter array declarators is not used for optimization. It might make sense to use it in future in conjunction with work on prefetching.
Гэцэцэ тупо игнорирует это слово, обещая, что когда-нибудь в будущем (через 100500 версий) это слово будет влиять на оптимизацию.
с другой стороны, префетч когда он был мне нужен в либо в компайлерах глючил - либо в процах глючил (сегфолты или доп тормоза). я ему как то не сильно доверяю.
Вот такой у сишечки интуитивно понятный и запоминаемый синтаксис...
да я просто тормоз. может с третьего раза запомню.
¡Olvidarás!
жуй насвай, гнида
программирование на темплейтах и констэкспр решают меня косающиеся проблемы - там я даже сильно и не пытался запомнить (и реально даже не нужно т.к. ни один проект даже не с++11) но мозги сами по себе впитали. а синтакс там еще хуже.
1) в нодах можно хранить не только int
2) размер указателя можно вычислять в компайл-тайме из размера пула
Мы все видели, что ты можешь. Память только не забудь правильно почистить. А потом попробуй оформить свой генератор в реюзабельную библиотеку.
Я могу и напитон перейти, если память будет лень чистить. Вообще, в компилтайм-метушне на шаблонах нигде память не чистится вообще никак (ни руками, ни через GC) и при этом никого это особо не волнует, почему я об этом думать должен? Так что можно просто смело срать в память, а потом пусть оно само чистится операционкой после завершения процесса кодогенерации.
самые успешние кодогены которые я писал, они все были одно-целевые.
я написал как то раз генератор юнит тестов, который мог буквально всё. я пытался его еще чистым держать, но тим хотела больше - и через пару итераций все обросло говном. и на него через какое-то время просто забили, потому что всех задрало гадать какой комбинацией опций конфигурации достигается какой эффект. просто - им мало было. сложно - они не могут.
не писать в ручную приятно - но люди забывают что они теряют контроль над кодом. если переходишь какую то невидимую грань - то кодген становится говном, потому что на него больше не возможно полагатся.
ЗЫ а лисп сюда припихивать просто не правомерно. с убогим препроцессором ц/крестов, сравнинивать с лиспом просто нечестно.
в смысле - интересно сколько минут понадобится про-лисперу что бы написать интерпретатор ц?
ЗЫ гото?.. почитай книжки по компиляции - ты похоже пытаешь переизобрести BBs (basic blocks).
... хм. вспоминаю что сам подобным мозги себе разминал. остановился на том что лиспа сильно не знаю, и вещи типа указателей (передача по ссылке/по значению) сложно переносить (потому что их в лиспе в принципе нет).
Сразу видно, что ты на лиспе не пишешь, а гомоиконы в суе поминаешь. Лисперу бы такой синтаксис для присваивания точно бы в голову не пришёл. Потому что во всех лиспах это проверка на равенство (чисел).
Но поскольку я пытаюсь сишку сделать лиспом, проверка равенства у меня будет ==
Да и вот eval в контроллер же фиг впихнешь, раз там архитектура гарвардская. Разве что на шитом коде делать, но это для анскиллябр, к тому же много флеша отхавает
Знаю кучу людей (включая себя любимую), которые которые кудовские ядра генерят напитоне, схемке и прочих абсолютно анскилльных языках.
В haskell целые language-c и language-c-quote есть.
(Это было на другой работе)
И что? Ты же будешь гомоиконить на хосте, а на контроллер пихать уже готовый результат, параметризованный под конкретную задачу.
Тут главное как-то провести грань между компайлтаймом и рантаймом. И GC в компайлтайме -- это офигенно удобно. А в рантайме выжившие данные станут какими-нибудь массивами констант.
Да, я про это еще в 2017 году написал, посмотри выше мой комментарий.
> j123123 18.08.2017 16:02 # 0
> Для компилтайм-метушни можно и GC с жирным рантаймом поиспользовать, а когда все окончательно скомпилируется, можно и без GC сделать результат, чтоб в контроллер впихнуть.