LINUX.ORG.RU

Проверка значения на наличие его в enum'е

 


0

2

Понятное дело, что в рантайме у нас нет возможности определить, входит ли значение переменной в enum, поскольку никакого enum'а в рантайме нет. Но вот есть такая вещь, по структуре напоминающая дерево:

A
+-A1
+-A2
+-A3
|
B
+-B1
+-B2
|
C
+-C1
+-C2
+-C3
+-C4
+-C5

В enum я это записал в виде значений с масками. Для A маска 0x00010000, для B 0x00020000 и т.д. Получилось как-то так:

enum XXX
{
                         //A
   E_A1 = (0x00010001U), //+-A1
   E_A2 = (0x00010002U), //+-A2
   E_A3 = (0x00010003U), //+-A3
                         //|
                         //B
   E_B1 = (0x00020001U), //+-B1
   E_B2 = (0x00020002U), //+-B2
                         //|
                         //C
   E_C1 = (0x00030001U), //+-C1
   E_C2 = (0x00030002U), //+-C2
   E_C3 = (0x00030003U), //+-C3
   E_C4 = (0x00030004U), //+-C4
}
Теперь такой момент - я читаю из файла значения (далее х и y) типа (A, B, C) и подтипа (для A - A1, A2, A3 и пр.) в виде int значений. Мне нужно проверить эти значения на адекватность, по сути выявить принадлежность (x << 16) | y к enum'у со значениями.

Я знаю такой не самый оптимальный метод: завести множесто мелких enum'ов для подтипов и один enum для перечисления типов. В каждом сделать последним значением что-то типа *_COUNT или *_MAX и оставить с автонумерацией. Тогда в чтении с файла мне нжен большой switch по типу, потом расписывать проверки на принадлежность к каждом подтипу (то самое сравнение с *_COUNT/*_MAX)... Но это выглядит очень костыльным с точки зрения добавления новых типов/подтипов).

Как бы вы это решили?

★★

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

Понятное дело, что в рантайме у нас нет возможности определить, входит ли значение переменной в enum

Чойта? Задай значения enum (классически, между прочим) в виде степеней двойки и проверяй на здоровье. Заодно на халяву получишь set of enum

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

Чойта? Задай значения enum (классически, между прочим) в виде степеней двойки и проверяй на здоровье. Заодно на халяву получишь set of enum

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

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

по сути выявить принадлежность (x << 16) | y к enum'у со значениями.

Рассуждаешь о масках, а про маски и забыл. x & 03FF <- я уверен, что до 0x3ff хоть один бит засветится

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

Рассуждаешь о масках, а про маски и забыл. x & 03FF <- я уверен, что до 0x3ff хоть один бит засветится

Я как-то не очень въезжаю о чем вы вообще говорите. Кто светился?

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

не более 32х значений

Если тебе в енаме надо больше значений, скорее всего ты либо что-то делаешь не так, либо генерируешь код.

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

Я как-то не очень въезжаю о чем вы

О том же о чём и ты: enum и маски.

ziemin ★★
()

Классическое решение:

enum { A1, A2, A3, NumA } AXXX;
enum { B1, B2, NumB } BXXX;
Проверка соответственно элементарна:
    enum AXXX a;

    if (a < NumA) {
        /* ... */
    }

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

Неа. Не элементарна: typedef enum{ GET_CLOCK = 0x0faf, SET_CLOCK = 0x1aaa, SWITCH_IN = 0x2aba, ... }spi_clock_commands; Так что, никак, кроме средств препроцессора.

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

Спрашивали про enum (enumirate — т.е. последовательное перечисление). То, что ты привёл — это уже вырожденное и извращённое применение вместо define. ;)

PS: кстати, советую почитать сырцы Plan9 — там очень много классных и правильных вещей.

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

Так оно обычно и делается. Не писать же уйму define'ов! Еще удобство по сравнению с define'ами: препроцессор проверит варианты 'case' и выкинет сообщение об ошибке, если ты не написал default, но забыл какие-то варианты.

А если по порядку, то можно самым последним элементом написать что-то вроде THIS_IS_THE_END__THE_END_MY_FRIEND__THE_END и проверять ☺

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

Для switch и при использовании, как define-заменитель, не нужен maxval, про который спрашивал ТС.

А при использованию по назначению (последовательное перечисление), используется приведённое мной решение для определения maxval.

Пример: http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/wikifs/fs.c (грепать по Nfile)

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

Как бы вы это решили?

Ассоциативным массивом.

i-rinat ★★★★★
()

Можно попробовать как-то так:

#define SUBTYPE_SIZE(subtype) (sizeof(subtype)/sizeof(int)) 

uint32_t subtype_a[] = {E_A1,E_A2,E_A3};
uint32_t subtype_b[] = {E_B1,E_B2};
uint32_t subtype_c[] = {E_C1,E_C2,E_C3,E_C4};

uint32_t subtypes_max[]={
    SUBTYPE_SIZE(subtype_a), 
    SUBTYPE_SIZE(subtype_b),
    SUBTYPE_SIZE(subtype_c)
};

uint32_t types_max[]=SUBTYPE_SIZE(subtypes_max);
...

    // get subtype size by 
    uint16_t type = val >> 16;
    uint16_t subtype = 0xFFFF & val;

    if(type <= types_max){
       if(subtype <= subtypes_max[type-1] ){
       ...
       }
    }
    
zudwa
()
Ответ на: комментарий от beastie

там очень много классных и правильных вещей

struct Aux {
	String *name;
	Whist *w;
	int n;
	ulong t;
	String *s;
	Map *map;
};
firstgen(int i, Dir *d, void *aux)
{
	ulong t;
	Bogus *b;
	int num;
	Aux *a;

	b = aux;
	num = qidnum(b->path);
	a = b->a;
	t = a->w->doc[a->n].time;
//i -= a->w->ndoc;
//i -= Qraw;

Издеваетесь? Как такой код можно читать?

shdown
()

Тебе нужно делать так:

-Werror=switch-enum

Пример:

enum class MegaEnum : char
{
  P = 'p',
  E = 'e',
  N = 'n',
  I = 'i',
  S = 's',
};

int main()
{
  MegaEnum c{MegaEnum::S};
  switch(c)
  {
    case MegaEnum::P:
    case MegaEnum::E:
    case MegaEnum::N:
    case MegaEnum::I:
      std::cout << "It's a penis part!" << std::endl;
      break;
    default:
      std::cout << "ALARM! NOT A PENIS PART!" << std::endl;
      break;
  }
}
$ g++ -Werror=switch-enum -std=c++11 test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:15:9: error: enumeration value ‘S’ not handled in switch [-Werror=switch-enum]
   switch(c)
         ^
cc1plus: some warnings being treated as errors

Соответственно switch{} засовываешь в функцию. И оно у тебя будет проверяться на этапе компиляции (ну то есть не даст тебе пропустить при проверке ни одно значение из перечисления).

DELIRIUM ☆☆☆☆☆
()
Последнее исправление: DELIRIUM (всего исправлений: 2)
Ответ на: комментарий от beastie

for (veryImportantCounter_variable_which_is_integer = 0; ...)

Доведение до абсурда же :) Мне кажется, сам автор не сможет сходу понять, что такое «ulong t;», заглянув туда через N лет.

К тому же, именование непоследовательно: вот эти name, aux, path, num, time тоже можно было «сократить» — может, буквы закончились? Или просто кто-то запутался в них?

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

Автор уже не сможет, автор умер в 2011 году. :(

Но я сам придерживаясь этого стиля и пока что ни разу не путался.

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

и пока что ни разу не путался.

Насколько большие программы? Сколько по календарному времени разрабатываются?

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Я — плохой показатель. В лучшем случае пишу только для себя, любимого. ;) Но надеюсь, что сам Plan9 достаточный по размеру и времени проект.

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

нет, даже этот вариант и то лучше, чем тот, что выше: сразу ясно, что переменная делает, читабельность кода 100%. да, набирать долго, но это ерунда, а вот код выше вида

ulong t;
Bogus *b;

поделие, которому, даже в хеллоуворлдах не место: Студенты пишут быдлокод (им это сходит с рук)

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

Ты только что назвал Ritchie быдлокодером. ;)

beastie ★★★★★
()

Всем спасибо, решил через xmacro

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

В лучшем случае пишу только для себя

Опенсорс только для себя и можно писать, иначе мотивации нет.

А Plan9 это всё-таки исследовательский проект, авторы писали как им удобнее. Если живёшь в предметной области, то всё и так понятно, чего зря кнопки жать.

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