LINUX.ORG.RU

А как вы бы определили что установлено 2 и более флага одновременно?

 


2

3

Есть int, в котором хранится значения битовых флагов:

enum Flags
{
   F1 = 1,
   F2 = 2,
   F3 = 4,
   F4 = 8
}

Как бы вы определили, что установлены 2 или более флага одновременно? Я сделал так:

if (signum(var & F1) +
    signum(var & F2) +
    signum(var & F3) +
    signum(var & F4) > 1)
   return 1
else
   return 0;


Последнее исправление: cetjs2 (всего исправлений: 2)

var& (F1|F2) == (F1|F2)

хотя если колво, тога функцию с

isSet(var, flag) {
  return (var & flag != 0) ? 1 : 0;
}

// и

count = isSet(var, F1) + isSet(var, F2)

и т.п.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

Вполне себе решение.

Можно взять, например, gcc-изм __builtin_popcount или std::bitset::count в C++

buddhist ☕☕☕☕
()

Нужно подойти с другой стороны 2 и более флага одновременно это не один. Из свойств бит имеем - при вычитании из степени 2 единицы получим набор единичек меньших по степени. Соответственно если установлено более двух единиц это правило будет нарушено. Отсюда результат:

(x - 1) | x == x * 2 - 1 - если установлен один флаг. Если два, и более, то не выполняется.

Как-то так короче.

ziemin
()
#define B2(n)   n, n+1, n+1, n+2
#define B4(n)   B2(n),  B2(n+1), B2(n+1), B2(n+2)
   
int testflag2 (int var)
{
    static int bitcount [32] = { B4(0), B4(1) };
    return bitcount[var&15]>1;
}
anonymous
()

ох ёж. пора ++ ценик.

x&(x-1) гасит левый(младшейший) бит если бит токмо один то будет ноль если popcount>1 то не нулевой.

qulinxao
()
Последнее исправление: qulinxao (всего исправлений: 3)
Ответ на: комментарий от anonymous_sapiens

Я ожидал этой простыни в комментах :)

sambist
() автор топика
Ответ на: комментарий от ziemin

Думал о чем-то подобном, но в моем случае не проканало, ибо у меня в enum'е есть еще пара флагов, которые могут быть установлены и должны игнорироваться.

sambist
() автор топика

и кстати:

>1 или >= или «что установлены 3 или более флага одновременно»

anonymous
()
Ответ на: комментарий от sambist

Да там тогда простыня получится

От пары флагов простыни не получится (F1 и F2 не учитываются):

x &= !(F1 | F2);
return (x - 1) | x != x * 2 - 1;

Как-то так.

ziemin
()
Ответ на: комментарий от ziemin
/* E */ enum SmlLStyles
{
    SML_LINE_ONLYPOINTS    = (0x000001),
    SML_LINE_ALIASED       = (0x000002),
    SML_LINE_ANTIALIASED   = (0x000004),
    SML_LINE_NOFIRSTPIXEL  = (0x000008),
    SML_LINE_NOLASTPIXEL   = (0x000016)
};

проверяю наличие одновременно установленных SML_LINE_ONLYPOINTS, SML_LINE_ALIASED и SML_LINE_ANTIALIASED. Возможно еще с пяток флагов добавится, неизвестного мне пока назначения.

sambist
() автор топика
Ответ на: комментарий от sambist

Так а в чём суть? Проверить, стоят-ли все флаги, кроме SML_LINE_NOFIRSTPIXEL и SML_LINE_NOLASTPIXEL?

Вообще идея, что надо посчитать _количество_ флагов - какая-то странная.

legolegs
()

Навскидку:

return var && var > 2 && var != 4 && var != 8
Сейчас еще подумаю

alix
()
Ответ на: комментарий от sambist

Алсо биты лучше объявлять так:

enum foobar {
AAA = (1<<0),
BBB = (1<<1),
CCC = (1<<2),
DDD = (1<<3),
};

legolegs
()
Ответ на: комментарий от legolegs

Вообще идея, что надо посчитать _количество_ флагов - какая-то странная.

Но решаемая, см коменты тут: http://govnokod.ru/16375 там есть однострочник без циклов для подсчёта ненулевых бит. Но повторюсь, не это тебе надо.

legolegs
()
Ответ на: комментарий от legolegs

Вообще идея, что надо посчитать _количество_ флагов - какая-то странная.

Я не хотел городить вот такое условие (которое обновлять - сдохнешь прежде чем корректно еще один флаг добавишь). Объясняю зачем - ALIASING, ANTIALIASING и ONLYPIXELS не могут стоять вместе, только кто-то один.

sambist
() автор топика
Ответ на: комментарий от sambist

А какая разница?

Глаз резануло. Тут либо подчёркивать ёмкость хранения ведущими нулями либо просто писать 0x1, 0x2, ..., 0x10...

ziemin
()
Ответ на: комментарий от ziemin

Я привык писать 3 байта, потому что 4 байта как-то не напишешь (ибо enum будет сводиться к signed int, а писать 0x000034FF и потом в голове инстинктивно думать, что это u32...), два байта может оказаться мало (ибо там всего 16 флагов может поместиться), а три -в самый раз.

sambist
() автор топика
Ответ на: комментарий от sambist

ибо enum будет сводиться к signed int, а писать 0x000034FF

Какая разница, что к чему приводится, если ты задаёшь значения? 0x1 он что в signed, что в unsigned один хер 0x1.

ziemin
()

Я бы сделал без signum:

if ((((var&F1) != 0) + ((var&F2) != 0) + ((var&F3) != 0) + ((var&F4) != 0)) > 1)
или так:

if (((var&F1 ? 1:0) + (var&F2 ? 1:0) + (var&F3 ? 1:0) + (var&F4 ? 1:0)) > 1)

Второй вариант, пожалуй, «чище».

dvl36
()
Ответ на: комментарий от Eddy_Em

Этот вариант значительно лучше: ты можешь и 32 флага выставить!

При незначительной правке можно данную шнягу и на 64 бита расширить!

Eddy_Em
()

Делай как ядро linux - припиши каунтер и ин(де)кременть его. Все гениальное просто.

unt1tled
()
Ответ на: комментарий от sambist

С точки зрения читаемости лучший вариант, имхо:

int somefunc(flags) {
  int incompatibleflags = flags & (ALIASING|ANTIALIASING|ONLYPIXELS);
  if (incompatibleflags!=ALIASING &&
      incompatibleflags!=ANTIALIASING &&
      incompatibleflags!=ONLYPIXELS)
      return 1; //error

Вот именно так. Если уж у тебя от содержимого if такой баттхёрт, можно сократить

int isPow2(int a) {
  return !(a&(a-1));
}
int somefunc(flags) {
  int incompatibleflags = flags & (ALIASING|ANTIALIASING|ONLYPIXELS);
  if (!isPow2(incompatibleflags))
    return 1; //error

Но самым правильным способом будет совместимые опции сделать флагами, а несовместимые - отдельным enum { A=0, B=1, C=2, D=3 }.

legolegs
()
Последнее исправление: legolegs (всего исправлений: 1)
Ответ на: комментарий от legolegs

Но самым правильным способом будет совместимые опции сделать флагами, а несовместимые - отдельным enum

Помилуйте, у меня и так в функцию идет слишком много параметров.

/* E */ SmlErrors SmlRasterDrawTetrGR(SmlIndex index, SmlTetragon tetragon, SmlTetragon corners, SmlGradient grad, SmlFStyle fstyle, SmlLStyle lstyle);
И так использовал структуры чтобы не посылать x1 y1 x2 y2 ...

sambist
() автор топика
Ответ на: комментарий от sambist

Помилуйте, у меня и так в функцию идет слишком много параметров.

Ну если предметная область требует много параметров, то заметанием их под ковёр делу не поможешь.

legolegs
()
Ответ на: комментарий от legolegs

Не, ну а как иначе тут сделаешь? Индекс текстуры, координаты вершин, коэффициенты скругления углов, информация о градиенте, стиль заливки и стиль линии. Из всего перечисленного не структуры - это только индекс и два последних флага.

sambist
() автор топика
Ответ на: комментарий от sambist

Оформи всё это в структуру. Это полноценный state, а не просто параметры.

Deleted
()
Ответ на: комментарий от sambist

А засунуть параметры отрисовки в некую структуру «Рисуемый объект» почему не хочешь? Если их много можно даже индекс в массиве передавать (как ты, судя по всему, делаешь с текстурами).

И да - структуры хорошо бы по указателю (или ссылке в c++) передавать. Как бы так принято. А то они все в стек копируются.

ziemin
()
if (var & (F1 | F2 | F3))
anonymous
()
Ответ на: комментарий от sambist

Ну и добавь параметр к функции. Да, их много, ну будет ещё один. Всяко лучше, чем держать в голове, что некоторые флаги - не флаги вовсе, а режимы.

legolegs
()
Ответ на: комментарий от ziemin

У него рендер же, если для каждого пикселя по указателю ходить - производительность будет не ок. Структуры «настройки рисования» тут может быть полезна, но может и не быть, я бы лишнюю сущность порождал только если она действительно нужна. Например, если критична память, то можно «настройки рисования» (флаги и режим сглаживания) упаковать чуть ли не в один байт с помощью битовых полей. Но лучше не надо.

legolegs
()

Если с полем допустимо работать как с числом, то находим нужное в bit twiddling hacks (а там есть и вычисление числа единичных бит, и вообще всякое), иначе два флага - это не ноль и не один:

if (var && !(var == F1 || var == F2 || var == F3 || var == F4))

в общем случае - да, суммой, но вместо signum можно использовать !!

slovazap
()
return ((F1|F2)&~(F3|F4)) > 0;

Первая сумма «или» - какие из флагов проверяем, вторая - какие из них игнорируем/маскируем.

blexey
()
Последнее исправление: blexey (всего исправлений: 2)

Про смешивание флагов которые могут быть установлены вместе и которые исключают друг друга здесь уже писали.

Кроме этого. Какова логика установки флагов? Возможно, самое простое решение - не устанавливать больше одного флага из тех, что исключают друг друга?

Я бы предложил еще такое решение: для каждого флага завести-захардкодить маску несовместимости, в которой на месте несовместимых с этим флагом битов стоят единицы, а остальные нули. Флаг устанавливать только когда логическое «и» текущего состояния и маски несовместимости этого флага равно нулю.

bogus_result
()

Второе решение: устанавливать флаг так («текущее состояние» и (не «маска несовместимости флага»)) или «флаг» ) то есть снимать все несовместимые с этим флагом биты.

Но лучше бы разобраться с логикой установки флагов: как получается, что несовместимые флаги пытаются устанавливаться вместе?

bogus_result
()

В некоторых процессорах есть инструкция pop, заботающая за 1 такт.

Deleted
()
Ответ на: комментарий от bogus_result

Какова логика установки флагов? Возможно, самое простое решение - не устанавливать больше одного флага из тех, что исключают друг друга?

Это функция для библиотеки. Вызывать ее будет пользователь. Строю «защиту от дурака».

sambist
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.