tarnyagin: (Default)
[personal profile] tarnyagin
Получил добро на "взять и всё переписать", второй день не вылезаю с работы, плёнки проявляю.

Сегодня решал на удивление нетривиальную задачку. Есть таблица макр (привет, mPower), описывающих некую хрень, что-то вроде:

DECLARE_PROPERTY(SomePropertyName, /*... attributes */)
DECLARE_PROPERTY(SomeOtherProperty, /*... attributes */)
...
DECLARE_PROPERTY(SomePropertyName, /*... attributes */)
...


, где имена пропертей могут повторяться. Требуется составить длинную строку из множества текстового представления уникальных имён и дать интерфейс для получения смещения на конкретное имя по его названию. То есть в этом примере мне на выходе нужна строка:
"SomePropertyName\0SomeOtherProperty\0" и три числа: 0, 17 и 0.

Да, чуть не забыл, "маленькое" такое дополнение: периода компиляции, пожалуйста :).
Я, пожалуй, подчеркну. Периода компиляции.

Вот что получилось (адаптировано):

#include <stdio.h>
#include <type_traits>

/* Converts a value to a type */
template <int T>
struct IntToType
{
  enum {value = T};
};

/* Merges two types */
template <class T, class U>
struct MergeTypes
  : public T
  , public U
{};

/* Table entry; contains string just for the selected ID */
template <class Id>
struct TableEntry;

template <>
struct TableEntry<IntToType<0> >
{};

/* Check if the entries [1..Id] is convertable to the U* */
template <class Id, class U>
constexpr bool checkDuplicate(Id, U* ptr)
{
  return TableEntry<Id>::convertable(ptr) ? true : (
      checkDuplicate(IntToType<Id::value - 1>(), ptr));
}

/* Stop recursion. */
template <class U>
constexpr bool checkDuplicate(IntToType<0>, U* ptr)
{
  return false;
}

/* Deduct return type for makeStringTable */
template<class T>
struct string_table_t
{
  typedef typename std::conditional<
    /* Check for duplicate. */
    !checkDuplicate(IntToType<T::value - 1>(), (typename TableEntry<T>::type_t*)NULL),
    /* Include the entry if the duplicate is not found */
    MergeTypes<decltype(makeStringTable(IntToType<T::value - 1>())), TableEntry<T> >,
    /* Skip the entry if the duplicate is found */
    decltype(makeStringTable(IntToType<T::value - 1>()))
  >::type type;
};

/* Stop recursion */
template<>
struct string_table_t<IntToType<0> >
{
  typedef TableEntry<IntToType<0> > type;
};

/* Recursively make the table. */
template <class T>
constexpr typename string_table_t<T>::type makeStringTable(T)
{
  return MergeTypes<
    decltype(makeStringTable(IntToType<T::value - 1>())),
    TableEntry<T>
  >();
}

/* Stop recursion */
template <>
constexpr TableEntry<IntToType<0> > makeStringTable(IntToType<0> t)
{
  return TableEntry<IntToType<0> >();
}

#define DECLARE_NAME(id, name)                                \
struct TableSelector_ ## name ## _t;                          \
template <>                                                   \
struct TableEntry<IntToType<id> >                             \
{                                                             \
  typedef TableSelector_ ## name ##  _t type_t;               \
  typedef TableEntry<IntToType<id> > name ## _t;              \
  const char name[sizeof(#name)] = #name;                     \
  static constexpr bool convertable(const void *) {           \
    return false;                                             \
  }                                                           \
  static constexpr bool convertable(                          \
      const TableSelector_ ## name ## _t *) {                 \
    return true;                                              \
  }                                                           \
  static constexpr int raw_offset =                           \
    sizeof(makeStringTable(IntToType<id - 1>()));             \
  static constexpr int offset = (raw_offset == 1) ?           \
    0 : raw_offset;                                           \
}

#if 1
/* Test table: */

DECLARE_NAME(1, test2test);
DECLARE_NAME(2, test4test);
DECLARE_NAME(3, test2test);
DECLARE_NAME(4, test3test);
DECLARE_NAME(5, test5test);


int main(int argc, char **argv)
{
  typedef string_table_t<IntToType<5> >::type table_t;

  static const table_t obj = makeStringTable(IntToType<5>());
  fwrite(&obj, sizeof(obj), 1, stdout);

  printf("\n");
  printf("test2test lays at offset %d\n",
    table_t::test2test_t::offset);
  printf("test4test lays at offset %d\n",
    table_t::test4test_t::offset);
  printf("test3test lays at offset %d\n",
    table_t::test3test_t::offset);
  printf("test5test lays at offset %d\n",
    table_t::test5test_t::offset);
  return 0;
}
#endif


Profile

tarnyagin: (Default)
Dmitry Tarnyagin

October 2017

S M T W T F S
12345 67
891011121314
15 161718192021
22232425262728
293031    

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 21st, 2025 06:11 am
Powered by Dreamwidth Studios