Динамический хеш-> тег класса

Я имею:

const unsigned int hash_1 = 0xaf019b0c;
const unsigned int hash_2 = 0xf864e55c;  
const unsigned int hash_3 = 0xfaea8ed5;

Хеши прибывают из автоматически сгенерированного заголовка. Эти хеши косвенно связаны с тегами 1, 2, 3. Теги связаны с классами через сгенерированный идентификатор простого времени компиляции. Тем путем я могу GetTag<Class1>() и получите мой международный тег для Class1.

Моя цель состоит в том, чтобы упростить хеш-> ассоциация тега. Предпочтительно это должно быть сгенерированным временем компиляции и O (1) время доступа. Память в этом случае не является проблемой. Я не могу использовать стороннее программное обеспечение.

Я попробовал следующее:

template<uint32 t>  size_t GetTagByHash() { return 0; }

с определенными реализациями как:

template<> size_t GetTagByHash<hash_1>() { return GetTag<Class1>(); }

но такую реализацию трудно использовать с тех пор, если у меня есть локальная переменная uint32 my_hash; то, что компилятор не может определить то, что оценивает его, имеет во время компиляции затем, компилятор не может разрешить корректную реализацию GetTagByHash() звонить.

1
задан Brooks Moses 23 July 2010 в 18:31
поделиться

1 ответ

Как я понимаю, ваша проблема в том, как сделать этот поиск со значениями времени выполнения и времени компиляции.

На самом деле у вас два вопроса. Во-первых, какой алгоритм вы хотите использовать для поиска, а во-вторых, как сказать C++, чтобы он был реализован?

Алгоритм для использования - это несколько неочевидный вопрос; у вас есть список эффективно случайных чисел, и вы хотите найти что-то в этом списке и вернуть соответствующий тег. Вероятно, вам нужна какая-то хэш-таблица, но для начала я покажу несколько примеров с чем-то более простым - и, вероятно, лучшим для небольшого числа хэшей: Простой O(N) поиск, в псевдокоде:

if i = N return tag_N
else if i = N-1 ...
...
else if i = 1 return tag_1
else return tag_0

Итак, как вы скажете C++ сделать это? Вы должны создать список всех ваших хэш-тегов и инструкции для этого. Вот простой способ:

template<int i> struct lookup
{
  int result(int j) { return 0; }
};

const unsigned int hash_1 = 0xaf019b0c;
template<> struct lookup<1>
{
  int result(int j)
  {
    if (j == hash_1)
      return GetTag<Class1>();
    return lookup<0>::result(j);
  }
};

const unsigned int hash_2 = 0xf864e55c;
template<> struct lookup<2>
{
  int result(int j)
  {
    if (j == hash_2)
      return GetTag<Class2>();
    return lookup<1>::result(j);
  }
};

И так далее. Затем, в конце, вы можете иметь

int hash_lookup(int j)
{
  return lookup<last_hash_number>::result(j);
}

Запись всех этих одинаковых определений - это, однако, боль, поэтому лучше позволить C++ сделать это - и, чтобы сделать это, вы должны определить хэши таким образом, чтобы их можно было итерировать. Давайте сделаем это:

template<int> struct hash_tag {
  static const int value = 0;
  typedef type void;
};

#define SET_HASH(I, VALUE, CLASS)   \
template<> struct hash_tag<(I)>     \
{                                   \
  static const int value = (VALUE); \
  typedef type (CLASS);             \
}

SET_HASH(1, 0xaf019b0c, Class1);
SET_HASH(2, 0xf864e55c, Class2);
SET_HASH(3, 0xfaea8ed5, Class3);

// Define a general recursive lookup struct.
template<int i> struct lookup
{
  int result(int j)
  {
    if (j == hash_tag<i>::value)
      return GetTag<hash_tag<i>::type>;
    return lookup<i-1>::result(j);
  }
};

// Make sure the recursion terminates.
template<> struct lookup<0>
{
  int result(int) { return 0; }
};

Затем, вы используете это, как и раньше.

Теперь давайте вернемся к первому вопросу - какой алгоритм вы хотите использовать для поиска? Преимущество этого итеративного O(N) поиска в том, что его легко программировать, и он не требует инициализации каких-либо структур данных во время выполнения - вы можете просто вызвать его. Однако, как уже отмечалось, это O(N). Альтернативным вариантом является использование объекта std::map; вы можете использовать аналогичное рекурсивное определение для его инициализации во время выполнения, а затем использовать его. Это может выглядеть примерно так:

// Make a typedef to save some typing.
typedef std::map<unsigned int, size_t> Map_type;
typedef std::pair<unsigned int, size_t> Map_value;

// Define a recursion to add hashes to the map.
template<int i> struct add_hash
{
  void add(Map_type& hashmap)
  {
    hashmap.insert(
      Map_value(hash_tag<i>::value, 
                GetTag<hash_tag<i>::type>));
    add_hash<i-1>::add(hashmap);
  }
};

// Make sure the recursion terminates.
template<> struct lookup<0>
{
  void add(Map_type&) {}
};

// Now, create a class to initialize the std::map and do lookup.
class Hash_lookup
{
  Hash_lookup() { add_hash<last_hash_number>(map_); }
  int result(unsigned int j) { return map_[j]; }
private:
  Map_type map_;
}

Лично я, вероятно, объединил бы это с вашей идеей GetTagByHash<>, и дал бы Hash_loop функцию "вычисляемый во время выполнения результат", как я описал, а также функцию "вычисляемый во время компиляции результат", которая принимает аргумент шаблона, а не аргумент функции. Но, в общем, это основная идея для выполнения поиска во время выполнения - вы помещаете значения, которые хотите найти, в набор шаблонизированных классов, которые вы можете рекурсивно итерировать во время компиляции, а затем вы используете эту рекурсивную итерацию для определения функции поиска или инициализации структуры времени выполнения, которую вы можете использовать для выполнения поиска.

2
ответ дан 2 September 2019 в 22:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: