LINUX.ORG.RU

Специальные значения типа для Generic-словаря

 , , , ,


0

2

Всех приветствую!

Приведу два примера, чтобы плавно подвести к вопросу.

ПРИМЕР1

Допустим есть словарь DICTIONARY<const char*, int> (Хотя и пишу на C буду использовать удобную нотацию из шаблонов C++)

У него есть ф-ция

int dict_find_value(DICTIONARY *dict, const char* key);

она возвращает значение типа int по заданному ключу.

Но возм. две ситуации 1 - словарь еще пустой 2 - такой ключ не найден

Что будет возвр. эта ф-ция в этих двух случаях?

Можно завести

#define DICT_KEY_NOT_FOUND INT_MAX
#define DICT_EMPTY         INT_MIN

и возвращать их в этих случаях.

Тогда проверки будут выглядеть так

if (DICT_KEY_NOT_FOUND != dict_find_value(&dict, key) )
// что-то делаем

ПРИМЕР2

Есть словарь DICTIONARY<const char*, void*>

Так же есть аналогичная ф-ция поиска

void* dict_find_value(UDICTIONARY *dict, const char* key)

которая возвр. два спец. значения

extern void* UDICT_KEY_NOT_FOUND;
extern void* UDICT_EMPTY;

...

UDICTIONARY*  udict_create(const size_t capacity)
{
...

	static int udnotfound;
	static int udempty;
	if (!UDICT_KEY_NOT_FOUND) UDICT_KEY_NOT_FOUND=&udnotfound;
	if (!UDICT_EMPTY)         UDICT_EMPTY=&udempty;
...
}

которые инициализируются (вполне конкр. значениями) при создании словаря.

А теперь вопрос.

Теперь есть обобщенный словарь UDICTIONARY<const char*, TYPE>

Какой TYPE пока еще не известно (может один из простых или структура).

Так вот как для него изящно завести эти два спец. значения?

Что-то вроде такого?

#define UDICT_KEY_NOT_FOUND(x)\
  _Generic( (x),            \
     int           : INT_MAX,     \
     float         : FLT_MAX,  \
     double        : DBL_MAX,   \
     struct POINT2 : (POINT2){.X=FLT_MAX, .Y=FLT_MAX},          \
     struct TRIANGLE_INDEX: (TRIANGLE_INDEX){.part=INT_MAX, .I=INT_MAX, .J=INT_MAX, .K=INT_MAX} \
     struct TYPE : (TYPE) {аналогично присваив. полям какие-то большие значения}
)

Или есть варианты лучше?

Заранее спасибо за внятные комментарии по существу вопроса.


Во-первых empty это частный и ничем не примечательный случай key not found, незачем ему отдельное значение придумывать.

Для указателей можно NULL возвращать. Остальным - зависит от ситуации. Часто целесообразно возвращать флаг ошибки и собственно результат отдельно друг от друга.

firkax ★★★★★
()

Возвращай указатель на значение в словаре. Т.е. для int это будет int*, а для void* - void**. Когда значение не найдено, возвращаешь nullptr. Никаких специальных значений.

rupert ★★★★★
()

ночь на понедельник :-)

вы изобретаете exception для C ??

хеш-мап и ассоциативные словари заводятся если подавляющая масса запросов приводят к позитивному результату (то есть что-то-там находят). В терминах цпп - всё прочее это исключения.

а так, в стиле классики Си

int dict_get_value(Dict *dict,void *key,void *save_value_here); // return 0 if ok, or non-zero error code
MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

хеш-мап и ассоциативные словари заводятся если подавляющая масса запросов приводят к позитивному результату (то есть что-то-там находят). В терминах цпп - всё прочее это исключения.

Странное заявление. Исключение кидает только метод at. Оператор [] вставляет новый элемент созданный конструктором по умолчанию, find возвращает итератор указывающий на конец.

anonymous
()
if (DICT_KEY_NOT_FOUND != dict_find_value(&dict, key) )
// что-то делаем

Если на каждый чих городить такое непотребство.

Что мешает сделать отдельные функции dict_contains(dict, key) dict_empty(dict), и функцию dict_get(dict, key) c UB, если ключ не найден? и не портить множество значений словаря специальными значениями? Атомарность?

if (!dict_empty(dict)) {
  if (dict_contains(dict, key)) {
    value = dict_get(dict, key);
  }
  else {
    // тут неопредленное поведение
    value = dict_get(dict, key);
  }
}

И вообще Си не запрещает возвращать структуры: можно возвращать код ошибки и значение в структуре. И не портить множество значений спец. значениями.

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

Если на каждый чих городить такое непотребство.

Я одной ф-цией dict_find_value могу и получить значение, и узнать что словарь пуст, и то что в нем нет требуемого ключа.

Это же хорошо?

И не портить множество значений спец. значениями

Всегда будут какие то значения которые не встретятся в реальных данных (ну кроме совсем маленьких типов типа char).

Я вот думаю м.б. возвращать пару pair<TYPE, bool>, где если не найден ключ, что bool = false, а возвр. значение равно ZERO_VALUE(x) (макрос нулевого значения для своих типов через _Generic)

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

Я одной ф-цией … могу

В Си одна функция main может всё. Разговор про всемогущество, или наоборот, делать одно (но хорошо)?

возвращать пару pair<TYPE, bool>

Можно возвращать аналог pair<TYPE*, enum dict_find_result>.

Указатель (ссылка) на TYPE, чтобы можно было менять значение по месту, заодно не копировать (тяжёлое) содержимое.

enum dict_find_result {
  Ok,
  Found = Ok,
  NotFound,
  Empty,
  ErrorВсёМогуДажеМогуНеМочь
}`.
anonymous
()
Ответ на: комментарий от Gyros

Я одной ф-цией dict_find_value могу и получить значение, и узнать что словарь пуст, и то что в нем нет требуемого ключа.

Это же хорошо?

А чоб тогда сразу не возвращать размер, следующий, предедущий элемент, последний добавленный и последний удалённый? Это же хорошо?

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

Обычно, если нужно отдельно обработать состояние что словарь пуст, это делается явной проверкой до обращения к элементу.

А у тебя, очевидно, во-первых, функция возвращающая элемент загажена логикой проверки размера словаря, которая выполняется на каждый вызов, нужна она или нет, и ещё логикой обработки этого случая чтобы вернуть специфический код. Во-вторых, клиентский код загажен обработками случая что словарь пуст на каждое обращение. В итоге сложный для понимания и неэффективный код и там и там.

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

хеш-мап и ассоциативные словари заводятся если подавляющая масса запросов приводят к позитивному результату (то есть что-то-там находят). В терминах цпп - всё прочее это исключения.

Господи, чего только не узнаешь на любимом лорчике…

anonymous
()