Это кажется возможным, но упаковано с раздражающими крайними случаями и некоторыми операциями, которые не совсем "хороши", хотя они технически избегают итерации.
Сначала приятная часть. Получение для каждой «группы» бита, указывающего, был ли включен какой-либо переключатель для этой группы. Подход может быть следующим: взять переключатели, вставить «блокировщик» 1 в бит сразу после группы и вычесть начальную точку каждой группы. Затем, если в группе не было установлено ни одного переключателя, «блокировщик» сбрасывается заимствованием. В противном случае, если есть набор переключателей, этот бит переключателя «съедает» заем, и блокировщик выживает. В коде:
runs_first = runs & ~(runs << 1);
runs_after = ~runs & (runs << 1);
toggles_blocked = toggles | runs_after;
selected_groups = runs_after & (toggles_blocked - runs_first);
Пример с вашими номерами (с префиксом ноль, чтобы избежать неудачного крайнего случая):
runs : 01111011010100011
toggles : 01010001010010110
runs_first : 00001001010100001
runs_after : 10000100101000100
toggles_blocked: 11010101111010110
difference : 11001100100110101
selected_groups: 10000100100000100
Если бы группы были фиксированной длины, это было бы Теперь можно легко расширить эти одноразрядные флаги до целых групповых масок ... или, если бит был расположен в начале группы, это также было бы легко. Обращение битов дает решение, используя трюк вычитания:
rev_selected = reverse(selected_groups >> 1);
rev_runs = reverse(runs);
rev_runs_after = ~rev_runs & (rev_runs << 1);
rev_groupmask = (rev_runs_after - rev_selected) & rev_runs;
groupmask = reverse(rev_groupmask)
Но даже «эффективный реверс» не настолько эффективен, если для него нет прямой аппаратной поддержки (например, rbit
на ARM, grevi
на RIS C -V с расширением B).