Задача была довольно простая: подгружаемая в процесс длл должна считать из памяти процесса записанные там данные о классах и упорядочить их.
В данной задаче у нас нет возможности сделать это на стороне процесса, всё должна делать подгружаемая длл, зато в процессе есть функция, которую можно вызвать из длл, которая возвращает указатель на первый класс в списке, при чём каждый класс (кроме последнего) содержит в себе указатель на следующий класс. Вот как выглядит класс:
class ClientClass
{
public:
const char* m_pNetworkName;
Table* m_pTable;
ClientClass* m_pNext;
};
Table
в свою очередь тоже класс и содержит он структуры, в которых хранится информация о членах класса -
Prop
:
struct Table
{
Prop* m_pProps; // Указатель на массив Prop'ов
int m_iProps; // количество Prop в Table
char* m_pNetTableName;
};
struct Prop
{
char* m_pVarName; // название члена класса
Table* m_pDataTable;
int m_Offset; // смещение указателя Prop относительно указателя Table
};
Обратите внимание на то, что внутри
Prop
может оказаться
Table
, инфу из которой также нужно прочитать.
Считывать память нужно для двух целей: запись информации в текстовый файл и сохранение в статически выделенной памяти длл для дальнейшего использования.
Моя реализация записи в текстовый файл (макрос LOG записывает с новой строки string в текстовый файл):
std::vector<std::string> base_classes;
static int class_level{ 0 };
void WriteAllOffsetsInLog()
{
// получаем указатель на первый класс
auto cl_class = Cl->GetFirstClass();
if (!cl_class)
return;
// сохраняем имена основных классов, чтобы не перечислять их члены в дочерних классах
while (cl_class)
{
auto table = cl_class->m_pTable;
if (table && table->m_iProps)
base_classes.push_back(table->m_pNetTableName);
cl_class = cl_class->m_pNext;
}
// снова находим первый класс
cl_class = Cl->GetFirstClass();
if (!cl_class)
return;
while (cl_class)
{
auto table = cl_class->m_pTable;
if (table && table->m_iProps)
{
class_level = 1;
// эта функция работает со структурами table и props
WriteClass(table, cl_class->m_pNetworkName);
}
cl_class = cl_class->m_pNext;
}
}
void WriteClass(Table* table, std::string name, int off = 0)
{
// добавляем табы в строчку в зависимости от того, насколько глубоко расположен класс в общем дереве
std::string tabtab = std::string();
for (int w = 0; w < class_level - 1; w++)
tabtab += " ";
std::string define_class { tabtab };
define_class += "class ";
define_class += name;
for (int i = 0; i < table->m_iProps; i++)
{
auto prop = table->m_pProps[i];
// перечисляем включённые классы справа от имени дочернего
if (prop.m_Offset == NULL && prop.m_pDataTable && prop.m_pDataTable->m_iProps && IsBaseClass(prop.m_pDataTable))
{
define_class += " : public ";
define_class += prop.m_pDataTable->m_pNetTableName;
}
}
if (off) // указатель класса смещён относительно материнского класса
{
define_class += " // ";
define_class += to16(off);
}
LOG(define_class);
LOG(tabtab + "{");
LOG(tabtab + "public:");
записываем члены класса
for (int i = 0; i < table->m_iProps; i++)
{
auto intabtab = tabtab + " ";
auto prop = table->m_pProps[i];
auto offset = to16(prop.m_Offset);
auto new_table = prop.m_pDataTable;
if (new_table) // член класса оказался классом и нужно вызвать функцию, которая запишет члены этого класса
{
if (!prop.m_Offset && IsBaseClass(new_table)) // оказалось, это не член класса, а включённый класс который будет расписан отдельно
continue;
if (new_table->m_iProps)
{
class_level++;
WriteClass(new_table, new_table->m_pNetTableName, prop.m_Offset);
class_level--;
}
}
else if (prop.m_Offset) // это просто переменная, запишем её смещение указателя
{
std::string log = intabtab;
log += "uintptr_t ";
log += prop.m_pVarName;
log += " = ";
log += offset;
log += ";";
LOG(log);
}
}
LOG(tabtab + "};");
LOG("");
if (class_level == 1)
LOG("");
}
Подскажите, как этот код оптимизировать? Он не оптимизирован от слова совсем, профайлинг выявил, что больше всего времени занимают операции с std::vector.