GNAT -gnat95
Используя механизм сильных ссылок, реализовать потоки
За основу берётся пакет https://www.adaic.org/resources/add_content/standards/95lrm/ARM_HTML/RM-13-13-1.html. Более конкретно, оттуда импортируются типы. И по аналогии с теми методами делаются методы здесь.
Аналогично Sample_Reference, делаются два типа. Один — для наследования, Root_Stream_Referenced. Другой — обёртка Root_Stream для применения в будущих пакетах.
Для интеграции с Адой в одну сторону делается Ada_Stream, обёртка-наследник стандартного Ada.Streams.Root_Stream_Type. Обёртка не реализует по второму разу Root_Stream, а содержит её в публично доступном поле и просто делегирует вызовы методов.
В обратную сторону в общем случае не получится, и делается только один частный случай, File_Stream_Referenced, содержащий https://www.adaic.org/resources/add_content/standards/95lrm/ARM_HTML/RM-A-12-1.html.
Как и всегда при использовании механизма сильных ссылок, делаются попарно два типа, для динамической памяти File_Stream_Referenced и обёртка File_Stream. API изменяется.
procedure Create (File : in out File_Type;
Mode : in File_Mode := Out_File;
Name : in String := "";
Form : in String := "");
Задачу в первом приближении понял. Займусь несколько позже.
Сейчас занимаюсь векторами. К стати, в АДА2012 вектора могут работать с потоками. Реализовать эту функциональность для наших векторов?
Раньше мне вроде бы было всё понятно. Сейчас у меня новый уровень понимания -- почти ничего не понятно. Зачем множить ссылки на файл? Лишь для того, чтобы деструктор в конце закрыл файл? Или каждый экземпляр ссылки должен иметь свои собственные атрибуты (типа позиции файла и моды файла)? Тогда нужно ли вводить спин-блокировку на операции, изменяющие эти атрибуты? Как нужно порождать новые экземпляры ссылок, специальной функцией типа "New_Instance" или простым копированием ссылки? Нужно ли вводить процедуру отсоединения ссылки от файла типа "Release_Instance" или "Detach_Instance"? Как реализовывать функциональность пакета, простым вызовом процедур из пакета "Ada.Streams.Stream_IO" или разработать независимую реализацию? И это, думаю, далеко не полный список вопросов.
Насколько я понял, задача такова:
Упрятать значение типа "Ada.Streams.Stream_IO.File_Type" в объект некого другого типа, имеющий счётчик инстанций. Новые инстанции открытого объекта получать простой операцией присвоения.
А как назвать новый тип? Может быть "Referenced_File"?
New_Stream : File_Stream := Open (выражение типа Wide_Wide_String, режим файла);
Я тут подумал, что на будущее стоит ввести в пакет "Unbounded_Array" процедуры работы с UTF16, чтобы потом реализовать открытие и работу с файловыми потоками через стандартную СИ-шную библиотеку которая поддерживает UTF16.
Я проанализировал открытие файла потока в реализациях GNAT и в AdaMagic, и пришёл к выводу что заморачиваться с UTF16 не имеет смысла. Функция _wfopen имеется только в СИ-библиотеке MSVCRT. В GNAT дескриптор потока AFCB имеет поле Encoding, которое описывает кодировку поля имени. По умолчанию это -- UTF-8. Само открытие потока осуществляется функцией fopen (импортируемое имя "__gnat_fopen"), которая третьим параметром имеет значение Encoding. Эта функция анализирует соответствующие условия в целевой ОС и осуществляет перекодировку строки имени файла с помощью функций библиотеки libiconv. Так что в GNAT нет проблем с открытием потока с UNICODE-именем. В стандартной реализации исполняющей библиотеке AdaMagic просто вызывается функция fopen из <stdio.h>, которая обычно не воспринимает UNICODE-имени. Так что AdaMagic нужно переопределить реализацию открытия потока и эта реализация будет зависеть от целевой ОС.
Я реализовал задание в пакете "File_Stream_IO". О том, что явный вызов процедуры "Close" не нужен, я помнил, а о процедуре "Delete" забыл. Реализовав эту процедуру, я долго думал как устранить конфликты между инстанциями потока в результате вызова процедуры "Delete". Посмотрел первоначальное задание и просто удалил реализацию этой процедуры. Как это у вас получается -- предусматривать всё на свете?
При реализации процедур с UNICODE-именами я как бы предположил, что стандартный пакет "Ada.Streams.Stream_IO" воспринимает эти имена в кодировке UTF-8. Для GNAT -- это верно, а для других компиляторов может потребоваться отдельная реализация этих процедур.
Жду дальнейших заданий.
UTF-16 в рантаймах, сейчас мне кажется, не надо
Либо дубовая ASCII поверх стандартного API сейчас. Либо конкретно забуриться в системное API и сделать как следует. Тратить время на промежуточные решения не требуются
Я уже говорил, что с UTF-16 не стоит заморачиваться. Лучше сделать как в GNAT. Там анализируется текущая локаль и делается перекодировка с помощью функций библиотеки LIBICOVN. Кстати, ASCII -- подмножество UTF-8.
В других своих проектах, которые заточены под GNAT, я объявил константу для Form и активно этим пользуюсь, но сейчас не готов делать на это ставку.
Вот, например, gprbuild, помню, перестаёт работать, если где-то в пути есть кириллица. Где-то как UTF-8 всё прочиталось, а где-то забыли, и в другое API всё пошло, где как ANSI интерпретация. Если не размежеваться с однобайтовыми кодировками, этот раздрай так и будет. Уж либо не делать, либо делать как следует.
Сейчас как следует делается наше API, а реализация не делается никак. 32битные символы, которыми задаётся имя файла, нужно через mod 256 приводить к номеру символа Character. Это моё текущее понимание «никак»
Я подключил API из нашего пакета Unbounded_Array и для ASCII оно так и получится.