Немножко кода, совсем чуть-чуть
Mar. 3rd, 2015 09:59 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Получил добро на "взять и всё переписать", второй день не вылезаю с работы, плёнки проявляю.
Сегодня решал на удивление нетривиальную задачку. Есть таблица макр (привет, mPower), описывающих некую хрень, что-то вроде:
, где имена пропертей могут повторяться. Требуется составить длинную строку из множества текстового представления уникальных имён и дать интерфейс для получения смещения на конкретное имя по его названию. То есть в этом примере мне на выходе нужна строка:
"SomePropertyName\0SomeOtherProperty\0" и три числа: 0, 17 и 0.
Да, чуть не забыл, "маленькое" такое дополнение: периода компиляции, пожалуйста :).
Я, пожалуй, подчеркну. Периода компиляции.
Вот что получилось (адаптировано):
Сегодня решал на удивление нетривиальную задачку. Есть таблица макр (привет, 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