C API Design для иерархии на диске - лучшие практики - PullRequest
2 голосов
/ 21 апреля 2009

Я пишу свой первый крупный C API, и я хочу, чтобы все было правильно. Библиотека выделяет и освобождает память для внутренней структуры, которая скрыта от клиента с помощью typedef. Примерная структура данных, к которым я предоставляю доступ, такова:

DISC-> програмно> трек

С диском связаны такие вещи, как дескриптор файла для чтения, размер файла, количество программ и некоторые свойства диска.

С программами связаны такие вещи, как (программный) индекс на диске, физическое смещение в файле, количество дорожек и имя.

С треками связаны такие вещи, как (трековый) индекс в программе, имя и куча смещений в файле.

Каждая структура имеет указатель на родительскую структуру.

У меня есть несколько вопросов, но я постараюсь быть кратким:

  • Должна ли дорожка / программа знать, по какому индексу она находится в родительской структуре?
  • Эта иерархия структур кажется довольно сложной, но альтернативой является передача индекса программы и / или трека различным функциям. Что предпочтительнее?
  • Есть еще общие комментарии?

Это структура, похожая на файловую систему (но она только для чтения), я хотел бы, чтобы она была совместима с многопоточностью в будущем, и она должна быть переносимой. Я специально говорю о C здесь - нет C ++.

Ответы [ 2 ]

3 голосов
/ 21 апреля 2009

Сильно отредактированное вступление Сначала я раскритиковал описание проблемы как сбивающее с толку. Мои проблемы проистекают из того, как в вопросе используется понятие «файл». Вопрос подразумевает, что диск, программы и дорожки хранятся в одном «файле». Я думал, что спрашивающий строит свою собственную файловую систему, что сделает эту структуру «все в одном файле» странной, но теперь я решил, что он, вероятно, этого не делает, и в этом случае это менее странно. Поэтому я продолжу и предложу реальный ответ, исходя из предположения, что он использует существующую (возможно, стандартную) файловую систему, и вся его структура данных хранится в одном файле в этой файловой системе. Если я ошибаюсь, без сомнения, меня поправят.

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

Один из способов работы над дизайном API - сначала написать некоторый код пользователя и определить API, чтобы его было легко писать. В качестве бонуса, после того, как вы на самом деле реализуете API, у вас будет тестовый код, чтобы опробовать его.

Переходя к более конкретному совету;

Вот каталог трех типов данных в системе. Мы можем обращаться с ними как с абстрактными типами данных или «объектами», если вам нравится, и определять структуру с определением типа (скажем, DISC, PROGRAM, TRACK) для представления каждого из них.

disc = a collection of programs stored in a file
+-----------+
|file       |
+-----------+
|program    |
+-----------+
|program    |
+-----------+
|...        |
+-----------+
|program    |
+-----------+

program = a collection of tracks
+-----------+
|ptr->disc  |
+-----------+
|name       |
+-----------+
|file offset|
+-----------+
|track      |
+-----------+
|track      |
+-----------+
|...        |
+-----------+
|track      |
+-----------+

track = a collection of audio samples
+------------------+
|ptr->program      |
+------------------+
|name              |
+------------------+
|file offset+length|
+------------------+
|file offset+length|
+------------------+
|...               |
+------------------+
|file offset+length|
+------------------+

Я бы предложил, чтобы вы не заставляли пользователей выбирать данные из структур. Вы не можете на самом деле скрыть внутреннюю структуру структур в C (не перепрыгивая через обручи с приведением и т. Д.), Но вы можете предоставить семейство функций, которые позволяют вашим пользователям делать то, что им нужно, без доступа к содержимому абстрактных типов. самих себя. Например, наше семейство функций может выглядеть так:

// DISC functions
DISC      *dopen(  const char *disc_name );
void       dstats( int *ptr_nbr_programs, FILE **ptr_file );
void       dclose( DISC *disc );

// PROGRAM functions
PROGRAM   *popen_name( DISC *disc, const char *program_name );
PROGRAM   *popen_idx ( DISC *disc, int program_idx );
void       pstats( int *ptr_nbr_tracks );
void       pclose( PROGRAM *program );

// TRACK functions
TRACK     *topen_name( PROGRAM *program, const char *track_name );
TRACK     *topen_idx ( PROGRAM *program, int track_idx );
int        tread( unsigned char *buf, int nbytes_to_read );
void       tseek( unsigned long offset );
void       tclose( TRACK *track );

Все это должно быть достаточно самоочевидным - оно смоделировано на основе существующей стандартной парадигмы C FILE.

Сначала ваш пользователь получает ptr для DISC с помощью dopen (). Предполагая, что это работает (он вернет NULL, если это не так), он может получить любую глобальную информацию DISC с помощью dstats (). Более того, он может получить ptr для PROGAM в пределах DISC с одной из функций popen ().

С помощью ptr to PROGRAM он может продолжить детализацию и получить один трек с одной из функций семейства topen ().

Очень важным моментом является то, что вы не заставляете своего пользователя самому проходить по аудиофрагментам для получения данных из TRACK. Пользователь предоставляет буфер для чтения сэмплов, и при необходимости вы выполняете итерации по фрагментам для заполнения этого буфера. Функция tseek () обеспечивает ему произвольный доступ.

Я не пытался проработать детали каждого параметра и способы обработки ошибок и т. Д., Я просто представляю концепцию, которую нужно уточнить.

Обратите внимание, что парадигма «сэндвич» используется повсеместно. Вводные «открытые» и завершающие «закрывающие» бутербродные операции для каждого типа.

0 голосов
/ 21 апреля 2009
  • Должна ли дорожка / программа знать, по какому индексу она находится в родительской структуре?

Случайно, я не думаю, что есть какая-либо причина против этого. Трудно сказать без примеров ...

  • Эта иерархия структур кажется довольно сложной, но альтернатива прохождение программы и / или трек-индекса к различным функциям. Который предпочтительнее?

Можете ли вы привести примеры каждого из них? Даже пара объявлений функций может помочь прояснить ситуацию.

  • Есть еще общие замечания?

Если это действительно структура только для чтения, вам не нужно слишком беспокоиться о многопоточности в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...