12.4 Загрузка объектов — retrieve()

Предыдущая  Содержание  Следующая V*D*V

Кто читает имя класса, выделяет память объекту и вызывает geto(), чтобы заполнить его? Возможно странно, что это выполняется функцией retrieve(), которая декларируется в файле описания класса Object.d, но которая не является методом:

 

void * retrieve (FILE * fp); // object from file

 

retrieve() читает имя класса из потока как строку; каким-нибудь образом находит подходящий указатель описания класса; использует allocate(), чтобы выделить место для объекта; и просит geto() заполнить его. Поскольку заключительный указатель описания класса вставляет allocate(), geto() может в самом деле быть применён к выделенной области памяти:

 

struct classList { const char * name; const void * class; };

 

void * retrieve (FILE * fp) {

    char buf [BUFSIZ];

    static struct classList * cL;              // локальная копия

    static int cD = -1;                        // количество классов

 

    if (cD < 0)

        ... build classList in cL[0..cD-1] ...

    if (! cD)

        fputs("no classes known\n", stderr);

 

    else if (fp && ! feof(fp) && fscanf(fp, "%s", buf) == 1) {

        struct classList key, * p;

 

        key.name = buf;

        if (p = bsearch(& key, cL, cD, sizeof key,

                (int (*) (const void *, const void *)) cmp))

            return geto(allocate(p -> class), fp);

        fprintf(stderr, "%s: cannot retrieve\n", buf);

    }

    return 0;

}

 

retrieve() требуется список имён классов и указателей описаний классов. Описания классов указывают на методы и селекторы, то есть этот список действительно гарантирует, что retrieve() использует код классов, связанный с использованием программы. Если данные для объекта считаны, методы для объекта доступны в программе — geto() только один из них.

Откуда берётся список классов? Можно было бы создать его вручную, но в главе 9 мы видели munch, простую программу awk для извлечения имён классов из списка объектных модулей, создаваемого nm. Поскольку nm может быть применена к библиотеке объектных модулей, можно даже извлечь список классов, поддерживаемый всей библиотекой. Результатом является массив classes[] со списком указателей на функции инициализации класса, отсортированный по именам классов в алфавитном порядке.

retrieve() могла бы искать в этом списке, вызывая каждую функцию, чтобы получить инициализированное описание класса и применяя nameOf() к результату для получения строкового представления имени класса. Это не очень эффективно, если надо получить много объектов. Поэтому retrieve() создаёт собственный список следующим образом:

 

extern const void * (* classes[]) (void);   // munch

 

if (cD < 0) {

    for (cD = 0; classes[cD]; ++ cD)

        ;                                   // подсчёт классов

    if (cD > 0) {                           // собираем имена/описания

        cL = malloc(cD * sizeof(struct classList));

        assert(cL);

        for (cD = 0; classes[cD]; ++ cD)

            cL[cD].class = classes[cD](),

            cL[cD].name = nameOf(cL[cD].class);

    }

}

 

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

 

Предыдущая  Содержание  Следующая