Архив рубрики: Статьи Руденко Олега

Ошибка компилятора С5-55

В очередной раз, «копаясь» во внутренностях Клары, обнаружил довольно неприятную ошибку порождаемую компилятором.

  Map
    MyFunc(),*STRING
  End

Str &STRING

  Code
  Str &= MyFunc()
  if ~(Str &= Null) then Message(Str).
  Return

MyFunc Procedure

  Code
  Return Null

Стандартная, казалось-бы, ситуация.
Есть функция, которая возвращает указатель на строку. Неважно, как она формирует эту строку. Важно (ОЧЕНЬ!!!), что она может вернуть нулевой указатель, если, например, из-за ошибки она не смогла сформировать для возврата нужную строку. И в программе мы всегда можем после вызова данной функции проверить Читать далее

Некоторые вопросы по внутренней организации структур на базе GROUP

Здравствуйте, Алексей.

Заранее прошу прощения, если мое письмо заставило Вас оторваться от более важных дел!

Сразу оговорюсь — речь идет о версиях Clarion С5/C55.

Разбираясь с внутренней организацией структур типа GROUP/QUEUE/CLASS/FILE обратил внимание на некоторые особенности описания OVER-полей. Это, впрочем, касается только OVER-полей, размер которых МЕНЬШЕ перекрываемой ими структуры. В этом случае поле, следующее за таким OVER-полем, описывается также как OVER-поле.
Причем сдвиг для данного поля задается таким образом, что область перекрытия начинается с точки, равной Address(BaseField)+Size(OverField). Читать далее

Некоторые особенности работы QUEUE

Не так давно по эхам «пробегало» письмо, в котором автор сетовал на невозможность сортировки очереди по полям типа $STRING.

Это действительно так. Но! Это — не глюк Клариона! Это — особенность внутренней реализации структур, основанных на GROUP.

Дело в том, что структуры на основе GROUP имеют как бы двойной интерфейс доступа к полям.

Первый интерфейс — прямое обращение к полю структуры по его метке, которое обрабатывается компилятором на этапе создания программы. При этом, естественно, компилятору доступна ВСЯ информация по типам переменных. Соответственно этим типам ведется и работа с такими полями. Читать далее

Внутренняя реализация Клариона #3

СЧ> Я не совсем понял что есть «процедура обработки» и что она не обрабатывает?

«Процедура обработки» для View, как и для QUEUE кстати, это практически тот-же драйвер в терминологии FILE. Т.е. при инициализации обьекта типа View или Queue Кларой создается заголовок для них, строится описание их внутренней структуры и в заголовок записывается адрес точки входа в процедуру  обработки. Для Class, вероятно, так-же. Еще не смотрел. Для всех однотипных конструкций — одна и та-же процедура обработки. Читать далее

Внутренняя реализация Клариона #2

СЧ> Если выбирать, то второй, как более гибкий.
СЧ> Но лучше и тот и другой.
СЧ> И еще не забудь про JOIN — он более сложен чем описан у тебя.
СЧ> Лично меня сейчас в JOIN особенно интересует возможность
СЧ> включать/отключать INNER на ходу.

Ну JOIN не такой уж и сложный! По крайней мере — внутренне.
А если ты имеешь ввиду большую глубину вложенности или много JOIN на одинаковых уровнях, так это все реализуется как-бы автоматом. Главное — правильно научиться формировать главный и первый уровни View. А это я уже умею!
Что касается INNER — кто мешает управлять им через PROP:Inner?
Или я не правильно понял? И что значит «на ходу»?
Если ты имеешь ввиду — во время выборки, то ничего не получиться!
Все установки для View дают эффект ТОЛЬКО перед Open(View)!
После этого по этим установкам формируется результирующая выборка, которую и читают по Next/Previous. Читать далее

Внутренняя реализация Клариона

На днях, после того, как послал письмо с описанием внутренних структур File и Queue, опять решил вернуться к данной теме. Подумал — почему такие сложности с конвертацией файлов, в особенности TPS? Если для простого конвертирования файлов DAT можно легко воспользоваться старым добрым Filer`ом из поставки CPD21, то для TPS-файлов нет ничего  подобного.
А если и есть, то все они громоздкие, сложные и, что главное для нас, дорогие. Не справедливо?!
Вот и решил написать что-то подобное. И для этого пришлось уточнить формат всех тех
структур, которые описывал.

Сразу-же предупреждение тем, кто решил воспользоваться информацией из того письма, особенно Сергею Чушкину -верен формат ТОЛЬКО заголовка файла. Все остальное очень сильно изменилось с времен CDD30/CFD31! Читать далее

Некоторые наблюдения по QUEUE #2

Не так давно Сергей Чушкин спрашивал насчет паковки записей очередей в C5-C55. Тогда я ответил, что подробно еще не разбирался с очередями.

В общем, подошла и очередь очередей :)(Каламбурчик, однако!) Теперь могу сказать точно — паковка в очередях есть и она работает! Более подробно сам механизм:

При общем размере записи (без учета OVER-полей) до 127 байт (включительно) запись не пакуется.
Начиная с размера 128 байт запись пакуется по простому алгоритму:
При упаковке вся запись рассматривается как массив байтов, без различения полей и их типов. При этом все повторяющиеся байты заменяются на последовательность <длина,байт-образец>. Перед последовательностью, которую не удалось сжать таким образом, ставиться байт с установленным старшим битом. Все остальные биты этого байта используются для задания длины несжатой последовательности. При необходимости (для задания большой длины) к данному байту добавляются еще байты. Аналогично и для задания кол-ва повторений байта-образца.
Только теперь старший бит сброшен.

В общем случае, для любой очереди, в качестве управляющей информации, распределяется около 1Kb памяти. Это без учета динамических ключей и накладных расходов на каждую запись.
Накладные расходы на каждую запись составляют 28 байт.
Кстати, из этих 28 байт полезной инфы — только 12 байт!
Остальные 16 байт — инфа менеджера памяти. На каждый динамический ключ еще по 4 байта.
Для упакованных записей — еще 4 байта. Да и еще каждая запись (упакованная или нет) выравнивается на границу 8 байт. Т.е., в худшем случае — еще +7байт.
Вот такая арифметика!

Кстати, реализовано все это достаточно нетривиально.
В заголовке каждой записи есть указатель, с помощью которого, через таблицу дискрипторов, вызывается процедура для обработки данной записи. Для неупакованных и упакованных записей она разная. В общем случае, для всех записей очереди вызывается одна и та-же процедура. Но, никто ведь не мешает повесить на каждую запись свою, уникальную, процедуру обработки данной записи! Какие, однако, перспективы!

И, вообще, согласен полностью с, кажется А.Ивановым, что очереди в Кларион — это сила!
Если-бы еще найти как подменить внутреннюю процедуру сортировки на свою, тогда вообще был бы полный кайф!

Некоторые наблюдения по QUEUE

Возможно кому будут интересны некоторые выводы по работе очередей, которые (выводы) сформировались в результате небольшого «копания» в них. Все выводы относятся ТОЛЬКО к реализации очередей в версии C5bee.

Динамические ключи действительно существуют и работают.

При первом поиске (Get) по неключевому полю (полям) выполняется стандартный SORT по этому полю (полям). Результат данной виртуальной сортировки сохраняется в так называемом «динамическом ключе», который представляет собой обычный массив из указателей на физические записи очереди. Под указателем имеется ввиду НЕ номер записи в очереди а именно указатель на область памяти, где физически размещена запись. Это дает возможность не перестраивать повторно уже созданные динамические ключи при изменениях очереди, таких как Add/Put/Delete/Sort. Читать далее

Я знаю как можно работать напрямую с файловыми и QUEUE структурами

Я знаю как можно работать напрямую с файловыми и QUEUE структурами. Т.е. можно использовать их динамическое формирование/изменение/удаление.

Очередь в памяти представлена практически так-же как и описание файла.
Например, тип FILE — это указатель на область памяти, которую назовем, например, «заголовок файла». Формат этого заголовка остался практически неизменным со времен CDD30. Несколько изменились лишь типы некоторых полей и в C5 добавились несколько полей, назначение которых Читать далее