Какую структуру данных использовать для огромного, но постоянного словаря в C ++ - PullRequest
5 голосов
/ 17 сентября 2011

Я должен использовать огромный словарь с целочисленными (или перечислимыми) ключами и строковыми значениями. Но это абсолютно постоянно. Нет способа изменить во время выполнения. Есть ли способ (использование шаблонов и т. Д.) Для получения данных словаря во время компиляции вместо использования существующей структуры словаря?

Ответы [ 3 ]

5 голосов
/ 17 сентября 2011

Clang и LLVM решили вашу проблему, создав таблицы, содержащие их объекты, используя комбинацию генерации кода и хитрости препроцессора.

Вы можете пропустить любой шаг, в зависимости от ваших настроек.Например:

// records.inc
EXPAND_RECORD(Foo, "Foo", 4);
EXPAND_RECORD(Bar, "Bar", 18);
EXPAND_RECORD(Bar2, "Bar", 19);

Теперь вы можете сгенерировать enum:

// records.h
enum Record {

#define EXPAND_RECORD(Name, String, Value) Name,
#include "records.inc"
#undef EXPAND_RECORD

};

char const* getRecordName(Record r);
int getRecordValue(Record r);

// records.cpp

char const* getRecordName(Record r) {
  switch(r) {
#define EXPAND_RECORD(Name, String, Value) case Name: return String;
#include "records.inc"
#undef EXPAND_RECORD
  }

  abort(); // unreachable, or you can return a "null" value
}

int getRecordValue(Record r) {
  switch(r) {
#define EXPAND_RECORD(Name, String, Value) case Name: return Value;
#include "records.inc"
#undef EXPAND_RECORD
  }

  abort(); // unreachable, or you can return a "null" value
}

В Clang и LLVM используется фаза генерации кода для генерации .inc из более приятных файлов определений.

Это работает довольно хорошо ... но учтите, что любая модификация перечисления подразумевает полную перекомпиляцию.Возможно, вы захотите перейти к подходу «кодового набора», где перечисление используется внутренне, но никогда не просачивается наружу, и клиенту предоставляются стабильные значения (значения перечисления) (unsigned), чтобы старые клиенты могли ссылаться нановые библиотеки без перекомпиляции: они будут ограничены использованием старого набора кодов, что не проблема, если он стабилен.

3 голосов
/ 17 сентября 2011

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

template <int Index> struct Dictionary { static const char *entry; };

и исходный файл с множеством строк вида:

template <> const char *Dictionary<5>::entry = "Entry for five";

С другой стороны, вы действительно хотите сделать это с точки зрения обслуживания? Это влечет за собой перекомпиляцию для каждой измененной записи словаря и раздутых исполняемых размеров.

0 голосов
/ 17 сентября 2011

Как насчет автоматической генерации кода? Возьмите файл конфигурации или базу данных или любой другой источник и сгенерируйте код заголовка C ++ из этого. Это может выглядеть примерно так:

#define MYCONST_1 "#00ff00"
#define MYCONST_10 "My other configuration string"

Вы можете выполнить преобразование с помощью простого bash-скрипта или с помощью ruby ​​/ python (или C ++, если вы мазохист), это зависит от сложности вашего файла конфигурации.

Затем напишите несколько правил make для автоматического создания заголовочных файлов при изменении файла конфигурации.

...