понедельник, 29 июля 2013 г.

Offtopic. Грустно...

http://ru.wikipedia.org/wiki/AltaVista

-- одна из "первых" поисковых машин.

А PDP - одна из лучших архитектур. С ОЧЕНЬ "правильным" ассемблером. С которого ассемблировать в код - "не составляло труда". В отличии от ассемблеров IBM.

Ну по моему мнению.

Ни то, ни другое - не выжило в этом мире...

"Хорошесть" - это не критерий выживаемости...

Offtopic. Offtopic. Offtopic. Ну это - что-то

Ну это - что-то - http://www.delphifeeds.ru/index.php?option=com_content&view=article&id=4331:%D0%9F%D1%83%D1%82%D0%B5%D1%88%D0%B5%D1%81%D1%82%D0%B2%D0%B8%D0%B5%20%D0%BD%D0%B0%20%D0%90%D0%BB%D1%82%D0%B0%D0%B9.&catid=38:webdelphi&Itemid=59

http://www.webdelphi.ru/2013/07/puteshestvie-na-altaj/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+myDelphi+%28Delphi+%D0%B2+Internet%29

Я вот стараюсь от "лирики" воздерживаться. Но иногда - "прорывает". И я - собой недоволен обычно.. Но не так же уж... Чтобы на delphifeeds ;-) Хотя наверное - там иногда - не мешает разбавить - "жизнью" :-)

Рассказать может быть в блоге - как я верёвки на перевал Сары-Шах в 2006-м году вешал? И как я был НЕ ГОТОВ к этим скалам? И как я ненавижу работу на скалах?

И - "почему я не залез на Ама-Даблам"... Рассказать?

А так же - на Пик Ленина... И Белуху...

И что я делал на Эльбрусе или Казбеке...

На самом деле - глупости это всё....

Я знаю - ЗАЧЕМ я на Ама-Даблам не полез.. :-)

P.S. Пересматривая фильм К-2 - я понимаю (для себя), что Гарольду - нафиг не нужна была гора. Ему нужен Был Тейлор и "гора в нём". Как я теперь это понимаю. Так - бывает... Мы сами - не до конца рулим своими поступками и желаниями... Если вы поняли :-)

P.P.S. Было кстати несколько "поворотных" моментов в моей жизни, когда я "ради гор" сделал неправильный выбор. Но! Об этом - не стоит сожалеть. Это надо принимать. Как ОПЫТ.

P.P.P.S. Странно кстати - почему в посты Offtopic и "лирика" приходит обычно раза в три народу больше, чем в посты "по сути"....

Почему же Embarcadero сделала "анонимные" функции, но не сделала приведение локальных процедур к ПОЛНОЦЕННЫМ лямбдам?

Жаль кстати, что в Embarcadero - НЕДОДУМАЛИ и не додумались дать возможность превратить в ЛЯМБДЫ - ЛЮБЫЕ ЛОКАЛЬНЫЕ процедуры и функции. Очень жаль :-( Там же на самом деле - всё просто. Если бы я писал бы компилятор - я бы ОБЯЗАТЕЛЬНО бы это сделал. Там же по месту вызова на уровне компилятора МОЖНО "сварить" обёртку над локальной функцией. ЗАВЕРНУТЬ её вызов - в анонимную функцию. Чтобы она стала ПОЛНОЦЕННОЙ лямбдой. Там - ОДИН ШАГ. Ну просто - 5 мин на правку компилятора. А скорее "препроцессора".

procedure CallInner (aProc : reference to procedure);
begin
 aProc;
end;

procedure A;

 procedure Inner;
 begin
 end;

begin
 ...
 CallInner(@Inner);
end;

превращаем в:

procedure A;

 procedure Inner;
 begin
 end;

begin
 ...
 CallInner(procedure begin Inner end;);
end;

ВСЁ!!!

Даже компилятор править не надо. ТОЛЬКО - "препроцессор". А сколько "геморроя" - снимется.

P.S. Как в 32-х битах это делать - в общем-то - всё понятно - http://18delphi.blogspot.com/2013/03/blog-post_5929.html. А вот - 64 бита - вызывают вопросы :-( Ну не знаю я 64-х битного ассемблера :-(

Вот мне стало интересно. А к Прологу адепты функциональных языков с какими чувствами относятся?

Вот мне стало интересно. А к Прологу адепты функциональных языков с какими чувствами относятся?

пятница, 26 июля 2013 г.

"доступ к методам объекта delphi" - вот мне интересно - что имел в виду человек, когда искал это?

"доступ к методам объекта delphi" - вот мне интересно - что имел в виду человек, когда искал это?

Только о главном они по-моему не говорят - КАК и ЗАЧЕМ

Только о главном они по-моему не говорят - КАК и ЗАЧЕМ

http://www.ibm.com/developerworks/ru/library/321_uml/

Есть мол "такая нотация". UML называется. Но ЗАЧЕМ это нужно. И КАК применять - никто не говорит...

:-(

Начинаю верить в "теорию заговора". "Киты" ИТ - что-то знают, но СОЗНАТЕЛЬНО скрывают :-(

Но!

"Нельзя сказать, что любой DSL может и должен быть реализован как UML-профиль; существует действительно много случаев, когда UML может потерять нужные фундаментальные концепции, которые могли бы быть преобразованы в соответствующие DSL-концепции. Однако, исходя из универсальности UML, он может быть более широко применимым, чем многие могли бы подумать."

Что-то - там "рядом лежит"...

Написал им комментарий:
"Очень - "наукообразно". Но как говорил В. Б. Зернов - можно "для домохозяек"? Чтобы "технари" поняли. На какие "кнопки жать". Например - "что есть профили UML"?"

-- посмотрим - удалят или ответят.

Они кстати там про "микросхемы" (http://18delphi.blogspot.ru/2013/04/uml_19.html http://18delphi.blogspot.com/2013/04/uml_22.html) пишут, там где про "порты". Но уж больно сухо и "заумно".

Как говорил один мой коллега - "опространствить" это - СИЛЬНО СЛОЖНО. Особенно - "технарю".

Хотя - всё же - НА ПОВЕРХНОСТИ лежит. "Матрёшка".. "микросхемы"...

О чём это?

http://www.uml3.ru/library/uml-diagrams/uml-diagrams.html

Там по-моему - что-то умное. Ортогональное UML. Но не могу "схватить" - что...

Но вот это:

"Вообще говоря, в диаграмму можно было бы включить любые (допустимые) комбинации сущностей и отношений, но произвол в этом вопросе затруднил бы понимание моделей. Поэтому авторы UML определили набор рекомендуемых к использованию типов диаграмм, которые получили название канонических типов диаграмм. Обратите внимание, что диаграмм не являются частью UML, как и абзацы или параграфы не являются частью естественного языка. Канонические диаграммы UML - это сложившаяся практика группирования сущностей и отношений."....

Подражание. "Конструктивизм! Хоть имя дико, но мне ласкает слух оно..."

Кто не в курсе, читаем:
http://ilibrary.ru/text/1233/p.1/index.html

Но это - лирика. А вообще говоря - ещё хочется написать - посему конструктивизм в программировании, важнее, чем "синтаксический сахар" (http://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%81%D0%B0%D1%85%D0%B0%D1%80).

Конструктивизм - это возможность строить объекты и сущности из "кубиков". Например из примесей (http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)).

Или например из шаблонов (http://ru.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) или моделей (http://ru.wikipedia.org/wiki/UML).

Или например с помощью DSL (http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BC%D0%B5%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F).

"В рамках таких языков, как Forth и Lisp, всегда существовала, но не всегда использовалась возможность создания DSL-языков."

Ну и АОП (http://ru.wikipedia.org/wiki/%D0%90%D1%81%D0%BF%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5).

Пока - почитайте ссылки :-) Потом - продолжим....

Вот немного про "конструктивизм" от "себя" - http://18delphi.blogspot.ru/2013/04/uml_19.html

Заметки о Pascal, Delphi и Lazarus: Анонимные методы в Delphi

Заметки о Pascal, Delphi и Lazarus: Анонимные методы в Delphi: Перевод из справочной системы Delphi Как предполагает название, анонимный метод – это процедура или функция, с которой не связано имени. А...

P.S. Жаль кстати, что в Embarcadero - НЕДОДУМАЛИ и не додумались дать возможность превратить в ЛЯМБДЫ - ЛЮБЫЕ ЛОКАЛЬНЫЕ процедуры и функции. Очень жаль :-( Там же на самом деле - всё просто. Если бы я писал бы компилятор - я бы ОБЯЗАТЕЛЬНО бы это сделал. Там же по месту вызова на уровне компилятора МОЖНО "сварить" обёртку над локальной функцией. ЗАВЕРНУТЬ её вызов - в анонимную функцию. Чтобы она стала ПОЛНОЦЕННОЙ лямбдой. Там - ОДИН ШАГ. Ну просто - 5 мин на правку компилятора. А скорее "препроцессора".

procedure A;

 procedure Inner;
 begin
 end;

begin
 ...
 CallInner(@Inner);
end;

превращаем в:

procedure A;

 procedure Inner;
 begin
 end;

begin
 ...
 CallInner(procedure begin Inner end;);
end;

ВСЁ!!!

четверг, 25 июля 2013 г.

Степанов говорит на лекциях. По "слухам"

Степанов говорит на лекциях. По "слухам".

Я сам этого не слышал. Но - ВЕРЮ.

Он говорит - "единственный контейнер, который вам надо использовать это - std::vector, если у вас появилась потребность в другом контейнере, то это СКОРЕЕ ВСЕГО может означать, что ваша архитектура - неидеальна".

И ещё он говорит - "в любой программе - есть ДВЕ ФАЗЫ - фаза накопления данных и фаза их обработки".

Сначала мол накопите вектор, потом сделайте его УНИКАЛЬНЫМ, потом - отсортируйте. Если я всё правильно понял.

Я в общем - примерно так же считаю. Я в 90% случаев использую именно vector-подобные контейнеры.

Знаете - какое основное свойство std::set По мнению Степанова?

Знаете - какое основное свойство std::set По мнению Степанова? По "слухам". Сортированность? Уникальность элементов?

Я бы лично - НИКОГДА бы не догадался...

Типа лирика. У меня есть перед глазами пример

У меня есть перед глазами пример. Моего коллеги. Который вообще учился на "гуманитарной" специальности.

Он не знает и не слышал про такую "чушь" как принцип максимума Понтрягина. Он недавно только узнал про "нормальные формы". Он вряд ли слышал про "теорию управления" и "устойчивые многочлены".

Но он - ОЧЕНЬ хороший программист.

Он ВДУМЧИВ, усидчив. Внимателен к деталям. Знает, что такое "поставитm break-point" и зачем это нужно. Знает как трассировать код. И опять же - зачем это нужно.

Но вряд ли - хороший математик.

Но он - ХОРОШИЙ программист.

Он читает "правильных" людей. Практиков. Он понимает объяснения с полу-слова.

И он ГОТОВ к осознанию и восприятию чужих мыслей и "инструкций".

Он "въехал" в UML - "за пол-дня". А также в шаблоны кодогенерации. И не "ныл" как некоторые.

Ещё раз убеждаюсь, что программирование это - не наука. И тем более - не творчество. Это - ремесло.

То программирование, которым мы занимаемся.

Это - вдумчивость, усидчивость, самодисциплина, готовность следовать инструкциям. И готовность воспринимать чужой опыт.

Надеюсь, что никто не обидится, если узнает себя. Я - только хорошее сказал.

P.S. программирование это - умение долго и нудно складывать маленькие вещи в большую картины. Хотя "пазлы" - я не люблю.

Ещё вопрос: Ленивые вычисления и кешируемость - как-нибудь соотносятся?

Ещё вопрос: Ленивые вычисления (http://ru.wikipedia.org/wiki/%D0%9B%D0%B5%D0%BD%D0%B8%D0%B2%D1%8B%D0%B5_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F) и кешируемость (результата) - как-нибудь соотносятся?

P.S. ГЛУПЫЙ вопрос кстати я задал. ЛЮБАЯ функция - кешируема - по-определению. Если она не опирается на монады. Если я правильно всё понимаю.

Говорят - Степанов - "не любит" ООП

Говорят - Степанов (http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BF%D0%B0%D0%BD%D0%BE%D0%B2,_%D0%90%D0%BB%D0%B5%D0%BA%D1%81%D0%B0%D0%BD%D0%B4%D1%80_%D0%90%D0%BB%D0%B5%D0%BA%D1%81%D0%B0%D0%BD%D0%B4%D1%80%D0%BE%D0%B2%D0%B8%D1%87_(%D1%83%D1%87%D1%91%D0%BD%D1%8B%D0%B9)) - "не любит" ООП.

Он говорит что-то вроде - "STL - это не ООП, это - конструктивизм". Если я правильно понял.

В чём-то - я его понимаю. Но только "в чём-то".

среда, 24 июля 2013 г.

Может быть кто-то расскажет мне про монады?

http://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%BD%D0%B0%D0%B4%D0%B0_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)

Может быть кто-то расскажет мне про монады?

Идею я примерно понимаю.

Но вот - технические тонкости - что-то не схватываю.

Есть кому, что рассказать? Для "технарей".

С примерами из реальной жизни.

P.S. понятно, что функция - детерминирована относительно её параметров, а монада - нет. И что функцию можно даже кешировать относительно значений её параметров.

P.P.S. Любая глобальная переменная или ввод-вывод это монады? А функция использующая хотя бы одну монаду - тоже монада? Ну по индукции. А значит, что любая "программа" на функциональном языке использующая хотя бы одну монаду - тоже монада? Ну тоже по индукции.. Так?

P.P.P.S. Функция, зависящая от даты/времени - тоже монада?

Пояснение про "функциональные языки"

Навеяно вот этим - http://18delphi.blogspot.ru/2013/07/blog-post_20.html?showComment=1374677196002#c7262330173032690440

Друзья мои! Коллеги.

Я ЗНАЮ про функциональные языки и про Haskell (http://ru.wikipedia.org/wiki/Haskell) - в частности.

И я знаю про каррирование и замыкания. И использую их в ПОВСЕДНЕВНОЙ работе.

Я даже знаю про стрелку Пирса :-) Но это из другой оперы :-)

Но не надо меня пытаться "обратить в свою веру".

Я - атеист и интернационалист.

И по-жизни и в программировании.

Я приемлю различные подходы, но в меру и к месту.

Если уж речь заходит о синтаксисе - скажу:

Я когда-то давно плевался от РАЯ (http://ru.wikipedia.org/wiki/%D0%A0%D0%90%D0%AF).

Но на новом витке развития скажу - написание тестов "по-русски" (http://18delphi.blogspot.com/2013/07/blog-post_196.html) и программирование "по-русски" (http://18delphi.blogspot.com/2013/04/dsl.html) -  имеют БОЛЬШИЕ перспективы.

А так - рад ЛЮБЫМ вопросам и предложениям. Но лучше всё же в тему.

Модерировать - конечно же ничего не буду. Ну разве что только откровенное хамство. Но этого пока слава богу - не случалось.

P.S. Если кто вдруг хочет в соавторы - с радостью позову.

P.P.S Кстати уж если пишите "есть такие языки, которые позволяют то-то и то-то" - то не стесняйтесь - называйте их. Давайте ссылки. Я с радостью изучу. Может что и другим посоветую.

P.P.P.S. Что до "выразительности" Haskell -  я не считаю его "ВЫРАЗИТЕЛЬНЫМ". Прикольным - да. Эффективным - скорее всего. Немногословным - тоже скорее всего. Но не ВЫРАЗИТЕЛЬНЫМ. Моя трактовка "выразительности" - видимо несколько иная. Не в строках кода и не в литералах выражается "выразительность".

Что "выразительнее", это:

5 5 + .

или это

"Напечатать результат выражения '5 + 5'"

?

По моему - второе. Но это конечно моё мнение. Вот так и с Haskell. Но это тоже моё мнение.

По-моему - "самодокументируемость" кода - вот ЗАЛОГ "выразительности". Чтобы не просто "коротко записать", а чтобы читающему было понятно - о чём речь.

Хотя! "Серебряной пули" - нет. Об этом всегда надо помнить.

Но "самыми" выразительными я пока считаю UML и DSL.

P.P.P.P.S. Не надо мне только говорить про интегралы, теорию групп, теорию множеств, дивиргенцию или ротор, или скажем тензоры. Или принцип максимума Понтрягина (http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D1%83%D0%BC%D0%B0_%D0%9F%D0%BE%D0%BD%D1%82%D1%80%D1%8F%D0%B3%D0%B8%D0%BD%D0%B0#.D0.9F.D1.80.D0.B8.D0.BD.D1.86.D0.B8.D0.BF_.D0.BC.D0.B0.D0.BA.D1.81.D0.B8.D0.BC.D1.83.D0.BC.D0.B0_.D0.9F.D0.BE.D0.BD.D1.82.D1.80.D1.8F.D0.B3.D0.B8.D0.BD.D0.B0). Я это всё конечно изучал. Но я и их - не считаю "выразительными". Я - не математик и не физик. Я - "технарь". Пытающийся работать с "людьми". И мне лично "графическая нотация" и/или "программирование по-русски" - сильно ближе. Меня иногда вообще "воротит" от "закорючек" и акронимов. Хотя - всё в меру.

P.P.P.P.P.S. Декларативность это - ЗДОРОВО! Сам люблю её. Но если с декларативностью "не получается" - надо переходить к императивности. А не придумывать "монады". ИМХО.

Про монады немного тут - http://18delphi.blogspot.com/2013/07/blog-post_9746.html

Разговаривал сегодня с коллегой. Он тоже "не любит dfm"

Разговаривал сегодня с коллегой. Он тоже "не любит dfm". В их нынешнем виде. Приятно в общем. Что я не один такой.

Чего не хватает?

Для начала:
1. Валидации на уровне компиляции.
2. Метаинформации. В частности - IfDef и комментариев.
3. Относительных координат в приемлимом виде.
4. Вариативности классов инстанцирования компонент.

Дарю идею кодогенерации "на коленке"

Берём любую рисовалку UML, которая умеет сохранять что-то xml-подобное. Или XMI (http://ru.wikipedia.org/wiki/XMI).

Строим дерево разбора этого xml. К каждому элементу дерева применяем шаблонное преобразование. Получаем код.

понедельник, 22 июля 2013 г.

В дополнение к MDA и TDD - могу предложить UCD - UseCase Driven

В дополнение к MDA и TDD - могу предложить UCD - UseCase Driven.

Самое важное, что UseCase плавно "перетекает" в UseCaseRealization и является проектным классом системы.

Далее надо написать про синтез VCM и UseCase'ов.

P.S. Сегодня только коллеге рассказывал это устно. Было бы здорово - если бы и он что-нибудь написал бы по поводу.

воскресенье, 21 июля 2013 г.

Чужая статья. Опыт работы в немецкой команде

http://habrahabr.ru/post/185828/

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

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

"У немцев очень прагматичный подход к работе. Я долго не мог к этому привыкнуть, но потом мне это даже стало нравиться. Перед тем, как фича пойдет в производство, задается много вопросов «нафига?» и «зачем?». Первая версия продукта была выпущена со всеми возможными и невозможными урезаниями функционала. Тем не менее, такой подход позволяет очень быстро запустить хоть и маленький, но качественный продукт, а также не перегружать команду.

Роадмап в крупную клетку расписан надолго вперед. Отклонения бывают, но для этого должны быть очень веская причина, которая тщательно разжевывается всем членам команды. Таким образом, если и происходят изменения в планах, они нечасты, и их необходимость осознается всей командой."

суббота, 20 июля 2013 г.

Так смешно, что аж грустно

"Используете ли вы UML?"

http://habrahabr.ru/post/153353/

"Приходится пользоваться, но слава богу - не часто". Порвало...

Пояснение про контейнеры

Речь вот об этом - http://18delphi.blogspot.com/2013/07/2_18.html и http://18delphi.blogspot.com/2013/07/2.html

Говорят - "что-то ты мало объясняешь". Не понимаю правда чтобы такого объяснить. Но попробую.

Тем более, что движок блога так устроен, что сложно перемешивать "картинки", текст и код. Пусть "там" будет код и "картинки", а тут будет "объяснение".

Итак. Что собственно хотелось?

Хотелось нескольких вещей:
1. Проиллюстрировать реальное использование UML для "хардкорной" конечной разработки.
2. Проиллюстрировать возможность создания на Delphi параметризуемых контейнеров в стиле STL (http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D0%B0%D1%8F_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2).
3. Проиллюстрировать создание "атомарных" тестов для DUnit.
4. Чисто "технической". Поскольку всё так или иначе построено на контейнерах, то просто надо "набрать базу". Чтобы при дальнейшем повествовании к этому вопросу больше не возвращаться.

Итак. Что там написано:
1. Инкапсуляция работы с памятью во вспомогательный объект/record. Зачем? Да для начала просто для того, чтобы не "размазывать" GetMem/FreeMem etc по коду контейнера.
2. List.imp.pas - собственно абстрактный контейнер. Опирающийся на ЧЕТЫРЕ абстракции - _ItemType_ (тип элемента) и FreeItem (очистка элемента), FillItem (заполнение элементом ячейки памяти), IsSame (сравнение элементов на тождество). Собтвенно List "предполагает", что эти абстракции где-то определены.
3. Далее на основе указанных абстракций и объекта Tl3PtrLoc List выводит "стандартный" интерфейс контейнера. Такой как:
3.1 Count.
3.2 Capacity
3.3. Items[]
3.4 Insert
3.5 Delete
3.6 Add
3.7 IndexOf
Ну и несколько "косметических" дополнений:
3.8 First
3.9 Last
3.10 Clear
4. Далее там введён AtomicList - контейнер который умеет работать с натуральными числами. Он определяет абстракции IsSame, FreeItem, FillItem.
5. Далее (для примера) введено ТРИ контейнера с разными типами чисел - TIntegerList, TByteList, TInt64List. Они определяют абстракцию _ItemType_ в Integer, Byte, Int64, соответственно.
6. Далее введён "абстрактный" тест - ListTest. Который опирается на абстракцию _ListType_. Он умеет создавать контейнеры для тестирования.
7. Далее введён абстрактный тест AtomicListTest. О иллюстрирует тестирование контейнеров натуральных чисел.
8. Ну и далее введены конкретные тесты - IntegerListTest, ByteListTest, Int64ListTest. ни тестируют соответствующие конкретные контейнеры.
9. Отдельно введён абстрактный контейнер InterfaceRefList - список интерфейсов, управляющий временем жизни своих элементов через счётчик ссылок.
10. Далее для примера введён конкретный контейнер - TIUnknownRefList. Он на самом деле не самоцель, а ПРИМЕР. Для реальной жизни гораздо правильнее инстанцировать конкретные контейнеры параметризованные конкретными интерфейсами. Статическая проверка типов компилятором. Без всяких "шаманств", приведений типов и тем более QueryInterface.
11. Ну и ещё там есть "тест" - IUnknownRefListTest. Он правда пока ничего не делает - лишь создаёт соответствующий контейнер. Чтобы хотя бы проверить, что он компилируется. Тест - потом конечно же дополню.

Вот вкратце всё. Если что-то непонятно - задавайте вопросы. С радостью отвечу. Ну или продолжу пояснения.

пятница, 19 июля 2013 г.

Есть кстати ещё одна тема - кеширование объектов

Есть кстати ещё одна тема - кеширование объектов. Но она может показаться "заумной".

Подсчёт ссылок, текстовый редактор и Undo/Redo

Подсчёт ссылок, текстовый редактор и Undo/Redo.

Тут будет текст, объясняющий - откуда у меня родилось понимание того - зачем нужен подсчёт ссылок...

На основе редактора... И Undo/Redo...

четверг, 18 июля 2013 г.

Вопрос к безмолвствующей аудитории

Продолжать ещё про контейнеры и их тесты? Или сразу уже "прыгнуть" к MVC-like фреймворку создания приложений на Delphi? Или может к редактору? Или может к UseCase'ам? Или тему UML развить? Вообще что-то хоть интересно? Или всё в "пустоту"?

Или про "требования" попробовать написать?

Я могу и про контейнеры ещё с десяток постов написать. Но надо ли?

Кстати про publisher/subscriber - можно уже тоже писать - "база" тоже готова.
Понятно, что его можно построить на чём-то вроде TIUnknownPtrList ?

Или про operation/action.

Есть интерес - что именно писать? Ну чтобы не писать "в пустоту".

Писать-то я - по-любому буду. Графомания-с.. :-)

P.S.
Или может вообще "лирики" влить - например на тему - "почему я не считаю программирование "творческим процессом""? :-)

Или почему даже в "водопаде" решения принимаются "в стиле XP"?

Или "почему программистам нужны "чертежи""?

P.P.S. я похоже могу "генерировать" либо код, либо "лирику", но не то и то ВМЕСТЕ.

Конкретные контейнеры. Часть 2

Предыдущая серия была тут - http://18delphi.blogspot.com/2013/07/blog-post_8789.html
И тут - http://18delphi.blogspot.com/2013/07/2.html

Теперь посмотрим как видоизменились конкретные контейнеры.

Модель:


Код:

StandardAtomicList.imp.pas:

{$IfNDef StandardAtomicList_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "StandardAtomicList.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::FinalContainers::StandardAtomicList
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define StandardAtomicList_imp}
 _AtomicList_Parent_ = TRefcounted;
 {$Include ..\SandBox\AtomicList.imp.pas}
 _StandardAtomicList_ = {mixin} class(_AtomicList_)
 end;//_StandardAtomicList_

{$Else StandardAtomicList_imp}

{$Include ..\SandBox\AtomicList.imp.pas}


{$EndIf StandardAtomicList_imp}

IntegerList.pas:

unit IntegerList;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "IntegerList.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIntegerList
//
// Список Integer'ов
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include ..\SandBox\sbDefine.inc}

interface

uses
  Refcounted,
  Classes,
  l3PtrLoc
  ;

type
 _ItemType_ = Integer;
 {$Include ..\SandBox\StandardAtomicList.imp.pas}
 TIntegerList = class(_StandardAtomicList_)
  {* Список Integer'ов }
 end;//TIntegerList

implementation

uses
  RTLConsts,
  l3MemorySizeUtils
  ;

{$Include ..\SandBox\StandardAtomicList.imp.pas}

end.

Int64List.pas:

unit Int64List;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "Int64List.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TInt64List
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include ..\SandBox\sbDefine.inc}

interface

uses
  Refcounted,
  Classes,
  l3PtrLoc
  ;

type
 _ItemType_ = Int64;
 {$Include ..\SandBox\StandardAtomicList.imp.pas}
 TInt64List = class(_StandardAtomicList_)
 end;//TInt64List

implementation

uses
  RTLConsts,
  l3MemorySizeUtils
  ;

{$Include ..\SandBox\StandardAtomicList.imp.pas}

end.

ByteList.pas:

unit ByteList;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "ByteList.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TByteList
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include ..\SandBox\sbDefine.inc}

interface

uses
  Refcounted,
  Classes,
  l3PtrLoc
  ;

type
 _ItemType_ = Byte;
 {$Include ..\SandBox\StandardAtomicList.imp.pas}
 TByteList = class(_StandardAtomicList_)
 end;//TByteList

implementation

uses
  RTLConsts,
  l3MemorySizeUtils
  ;

{$Include ..\SandBox\StandardAtomicList.imp.pas}

end.

IUnknownRefList.pas:

unit IUnknownRefList;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "IUnknownRefList.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIUnknownRefList
//
// Список ССЫЛОК на IUnknown
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include ..\SandBox\sbDefine.inc}

interface

uses
  Refcounted,
  Classes,
  l3PtrLoc
  ;

type
 _ItemType_ = IUnknown;
 _InterfaceRefList_Parent_ = TRefcounted;
 {$Include ..\SandBox\InterfaceRefList.imp.pas}
 TIUnknownRefList = class(_InterfaceRefList_)
  {* Список ССЫЛОК на IUnknown }
 end;//TIUnknownRefList

implementation

uses
  RTLConsts,
  l3MemorySizeUtils
  ;

{$Include ..\SandBox\InterfaceRefList.imp.pas}

end.

IUnknownPtrList.pas:

unit IUnknownPtrList;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "IUnknownPtrList.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIUnknownPtrList
//
// Список УКАЗАТЕЛЕЙ на IUnknown
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include ..\SandBox\sbDefine.inc}

interface

uses
  Refcounted,
  Classes,
  l3PtrLoc
  ;

type
 _ItemType_ = IUnknown;
 _InterfacePtrList_Parent_ = TRefcounted;
 {$Include ..\SandBox\InterfacePtrList.imp.pas}
 TIUnknownPtrList = class(_InterfacePtrList_)
  {* Список УКАЗАТЕЛЕЙ на IUnknown }
 end;//TIUnknownPtrList

implementation

uses
  RTLConsts,
  l3MemorySizeUtils
  ;

{$Include ..\SandBox\InterfacePtrList.imp.pas}

end.

И тесты.

Модель:



Код:

ListTest.imp.pas:

{$IfNDef ListTest_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBoxTest"
// Модуль: "ListTest.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: TestCaseMixIn::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::ListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define ListTest_imp}
{$If defined(nsTest)}
 _ListTest_ = class(TTestCase)
 protected
 // protected methods
   function CreateList: _ListType_;
     {* Создаёт список для тестирования }
 end;//_ListTest_
{$IfEnd} //nsTest

{$Else ListTest_imp}

{$If defined(nsTest)}

// start class _ListTest_

function _ListTest_.CreateList: _ListType_;
//#UC START# *51E80E0D030D_51E80DD30125_var*
//#UC END# *51E80E0D030D_51E80DD30125_var*
begin
//#UC START# *51E80E0D030D_51E80DD30125_impl*
 Result := _ListType_.Create;
//#UC END# *51E80E0D030D_51E80DD30125_impl*
end;//_ListTest_.CreateList

{$IfEnd} //nsTest

{$EndIf ListTest_imp}

AtomicListTest.imp.pas:

{$IfNDef AtomicListTest_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBoxTest"
// Модуль: "AtomicListTest.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: TestCaseMixIn::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::AtomicListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define AtomicListTest_imp}
{$If defined(nsTest)}
 {$Include ..\SandBox\ListTest.imp.pas}
 _AtomicListTest_ = class(_ListTest_)
 private
 // private methods
   function RandomItem: _ItemType_;
 published
 // published methods
   procedure DoIt;
   procedure TestTwoLists;
   procedure TestInsert;
   procedure TestInsertAt0;
   procedure DeleteTest;
     {* Тест удаления элемента }
   procedure AddTest;
     {* Тест добавления элемента }
   procedure RemoveTest;
     {* Тест удаления элемента по значению }
 end;//_AtomicListTest_
{$IfEnd} //nsTest

{$Else AtomicListTest_imp}

{$If defined(nsTest)}

{$Include ..\SandBox\ListTest.imp.pas}

// start class _AtomicListTest_

function _AtomicListTest_.RandomItem: _ItemType_;
//#UC START# *51E6ADE0016E_51E03FC80111_var*
var
 l_V : Cardinal;
//#UC END# *51E6ADE0016E_51E03FC80111_var*
begin
//#UC START# *51E6ADE0016E_51E03FC80111_impl*
 l_V := Random(1000);
 if (l_V > High(_ItemType_)) then
  Result := High(_ItemType_)
 else
  Result := l_V;
//#UC END# *51E6ADE0016E_51E03FC80111_impl*
end;//_AtomicListTest_.RandomItem

procedure _AtomicListTest_.DoIt;
//#UC START# *51DEB319037C_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Count : IndexType;
 l_Index : IndexType;
//#UC END# *51DEB319037C_51E03FC80111_var*
begin
//#UC START# *51DEB319037C_51E03FC80111_impl*
 l_List := CreateList;
 try
  l_List.Count := cCount;
  Check(l_List.Count = cCount);
  Check(l_List.Capacity >= cCount);

  for l_Index := 0 to l_List.Count - 1 do
   Check(l_List[l_Index] = 0);

  l_Count := Random(cCount);
  l_List.Count := l_Count;
  Check(l_List.Count = l_Count, Format('Выделяли %d элементов. Count = %d', [l_Count, l_List.Count]));
  Check(l_List.Capacity >= l_Count, Format('Выделяли %d элементов. Capacity = %d', [l_Count, l_List.Capacity]));

  for l_Index := 0 to l_List.Count - 1 do
   Check(l_List[l_Index] = 0);
   
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51DEB319037C_51E03FC80111_impl*
end;//_AtomicListTest_.DoIt

procedure _AtomicListTest_.TestTwoLists;
//#UC START# *51DED6FC03C1_51E03FC80111_var*
const
 cCount = 1000;
var
 l_A : _ListType_;
 l_B : _ListType_;
 l_Index : IndexType;
 l_Value : _ItemType_;
//#UC END# *51DED6FC03C1_51E03FC80111_var*
begin
//#UC START# *51DED6FC03C1_51E03FC80111_impl*
 l_A := CreateList;
 try
  l_B := CreateList;
  try
   l_A.Count := cCount;
   for l_Index := 0 to l_A.Count - 1 do
   begin
    l_Value := RandomItem;
    l_A[l_Index] := l_Value;
    Check(l_A[l_Index] = l_Value);
   end;//for l_Index

   l_B.Count := l_A.Count;
   for l_Index := 0 to l_A.Count - 1 do
   begin
    l_B[l_Index] := l_A[l_Index];
   end;//for l_Index

   for l_Index := 0 to l_A.Count - 1 do
   begin
    Check(l_B[l_Index] = l_A[l_Index]);
   end;//for l_Index
  finally
   FreeAndNil(l_B);
  end;//try..finally
 finally
  FreeAndNil(l_A);
 end;//try..finally
//#UC END# *51DED6FC03C1_51E03FC80111_impl*
end;//_AtomicListTest_.TestTwoLists

procedure _AtomicListTest_.TestInsert;
//#UC START# *51E6AC74038B_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Value : _ItemType_;
 l_Index : IndexType;
//#UC END# *51E6AC74038B_51E03FC80111_var*
begin
//#UC START# *51E6AC74038B_51E03FC80111_impl*
 l_List := CreateList;
 try
  for l_Index := 0 to cCount do
  begin
   l_Value := RandomItem;
   l_List.Insert(l_Index, l_Value);
   Check(l_List.Count = l_Index + 1);
   Check(l_List[l_Index] = l_Value);
  end;//for l_Index
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51E6AC74038B_51E03FC80111_impl*
end;//_AtomicListTest_.TestInsert

procedure _AtomicListTest_.TestInsertAt0;
//#UC START# *51E6B4260008_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Value : _ItemType_;
 l_Index : IndexType;
//#UC END# *51E6B4260008_51E03FC80111_var*
begin
//#UC START# *51E6B4260008_51E03FC80111_impl*
 l_List := CreateList;
 try
  for l_Index := 0 to cCount do
  begin
   l_Value := RandomItem;
   l_List.Insert(0, l_Value);
   Check(l_List.Count = l_Index + 1);
   Check(l_List[0] = l_Value);
  end;//for l_Index
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51E6B4260008_51E03FC80111_impl*
end;//_AtomicListTest_.TestInsertAt0

procedure _AtomicListTest_.DeleteTest;
//#UC START# *51E7F6EF0285_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Value : _ItemType_;
 l_Index : IndexType;
 l_Prev : _ItemType_;
//#UC END# *51E7F6EF0285_51E03FC80111_var*
begin
//#UC START# *51E7F6EF0285_51E03FC80111_impl*
 l_List := CreateList;
 try
  for l_Index := 0 to cCount do
  begin
   l_Value := RandomItem;
   l_List.Insert(l_Index, l_Value);
   Check(l_List.Count = l_Index + 1);
   Check(l_List[l_Index] = l_Value);
  end;//for l_Index

  while not l_List.Empty do
  begin
   l_Index := Random(l_List.Count - 1);
   if (l_Index < l_List.Count - 1) then
   begin
    l_Prev := l_List[l_Index + 1];
    l_List.Delete(l_Index);
    if l_List.Empty then
     break;
    Check(l_List[l_Index] = l_Prev);
   end//l_Index < l_List.Count - 1
   else
   begin
    if (l_Index = 0) then
     l_List.Delete(l_Index)
    else
    begin
     l_Prev := l_List[l_Index - 1];
     l_List.Delete(l_Index);
     if l_List.Empty then
      break;
     Check(l_List[l_Index - 1] = l_Prev);
    end;//l_Index = 0
   end;//l_Index < l_List.Count - 1
  end;//while l_List.Count
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51E7F6EF0285_51E03FC80111_impl*
end;//_AtomicListTest_.DeleteTest

procedure _AtomicListTest_.AddTest;
//#UC START# *51E80DC50154_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Value : _ItemType_;
 l_Index : IndexType;
//#UC END# *51E80DC50154_51E03FC80111_var*
begin
//#UC START# *51E80DC50154_51E03FC80111_impl*
 l_List := CreateList;
 try
  for l_Index := 0 to cCount do
  begin
   l_Value := RandomItem;
   l_List.Add(l_Value);
   Check(l_List.Last = l_Value);
  end;//for l_Index
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51E80DC50154_51E03FC80111_impl*
end;//_AtomicListTest_.AddTest

procedure _AtomicListTest_.RemoveTest;
//#UC START# *51E8127802AF_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Value : _ItemType_;
 l_Index : IndexType;
//#UC END# *51E8127802AF_51E03FC80111_var*
begin
//#UC START# *51E8127802AF_51E03FC80111_impl*
 l_List := CreateList;
 try
  for l_Index := 0 to cCount do
  begin
   l_Value := RandomItem;
   l_List.Add(l_Value);
   Check(l_List.Last = l_Value);
  end;//for l_Index

  while not l_List.Empty do
  begin
   l_Value := RandomItem;
   l_List.Remove(l_Value);
  end;//while not
  
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51E8127802AF_51E03FC80111_impl*
end;//_AtomicListTest_.RemoveTest

{$IfEnd} //nsTest

{$EndIf AtomicListTest_imp}

IUnknownRefListTest.pas:

unit IUnknownRefListTest;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBoxTest"
// Модуль: "IUnknownRefListTest.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::IUnknownRefListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include ..\SandBox\sbtDefine.inc}

interface

{$If defined(nsTest)}
uses
  TestFrameWork,
  IUnknownRefList
  ;
{$IfEnd} //nsTest

{$If defined(nsTest)}
type
 _ListType_ = TIUnknownRefList;
 {$Include ..\SandBox\ListTest.imp.pas}
 TIUnknownRefListTest = class(_ListTest_)
 published
 // published methods
   procedure DoIt;
 end;//TIUnknownRefListTest
{$IfEnd} //nsTest

implementation

{$If defined(nsTest)}
uses
  SysUtils
  ;
{$IfEnd} //nsTest

{$If defined(nsTest)}

{$Include ..\SandBox\ListTest.imp.pas}

// start class TIUnknownRefListTest

procedure TIUnknownRefListTest.DoIt;
//#UC START# *51E80B2F02CF_51E80B08039E_var*
var
 l_List : _ListType_;
//#UC END# *51E80B2F02CF_51E80B08039E_var*
begin
//#UC START# *51E80B2F02CF_51E80B08039E_impl*
 l_List := CreateList;
 try
  // - Пока больше ничего не делаем
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51E80B2F02CF_51E80B08039E_impl*
end;//TIUnknownRefListTest.DoIt

{$IfEnd} //nsTest

initialization
 TestFramework.RegisterTest(TIUnknownRefListTest.Suite);

end.

Абстрактные контейнеры. Часть 2

Предыдущая серия была тут - http://18delphi.blogspot.com/2013/07/blog-post_3683.html

Расширим теперь функциональность контейнера. Добавив "стандартные" контейнерные операции.

Как всегда начнём с модели:

И код:

List.imp.pas:
{$IfNDef List_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "List.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::List
//
// Абстрактный список значений
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define List_imp}
 PItemType = ^_ItemType_;

const
  { Sizes }
 cItemSize = SizeOf(_ItemType_);

type
 IndexType = System.Integer;

 _List_ = {mixin} class(_List_Parent_)
  {* Абстрактный список значений }
 private
 // private fields
   f_Data : Tl3PtrLoc;
    {* Собственно место хранения данных}
   f_Count : IndexType;
    {* Поле для свойства Count}
 private
 // private methods
   procedure ReAllocList(aNewCapacity: IndexType);
   procedure CheckIndex(anIndex: IndexType); // can raise EListError
     {* проверяет валидность индекса и поднимает исключение, если он неправильный }
   function ItemSlot(anIndex: IndexType): PItemType;
   function ExpandSize(aTargetSize: IndexType): Cardinal;
   procedure CheckSetItem(anIndex: IndexType); // can raise EListError
     {* Проверяет валидность индекса при вставке }
   procedure DirectInsert(anIndex: IndexType;
     const anItem: _ItemType_);
     {* Непосредственная вставка элемента. Без проверки валидности индекса }
   procedure MoveItems(aDst: IndexType;
     aSrc: IndexType;
     aSize: Cardinal);
 protected
 // property methods
   procedure pm_SetCount(aValue: IndexType);
   function pm_GetCapacity: IndexType;
   procedure pm_SetCapacity(aValue: IndexType);
   function pm_GetItems(anIndex: IndexType): _ItemType_;
   procedure pm_SetItems(anIndex: IndexType; const aValue: _ItemType_);
   function pm_GetEmpty: Boolean;
   function pm_GetFirst: _ItemType_;
   function pm_GetLast: _ItemType_;
 protected
 // overridden protected methods
   procedure Cleanup; override;
     {* Функция очистки полей объекта. }
 public
 // public methods
   procedure Delete(anIndex: IndexType); // can raise EListError
     {* удалить элемент с индексом anIndex }
   procedure Insert(anIndex: IndexType;
     const anItem: _ItemType_); // can raise EListError
     {* Вставка элемента }
   procedure Add(const anItem: _ItemType_);
     {* Добавляет элемент списка }
   function IndexOf(const anItem: _ItemType_): IndexType;
     {* Возвращает индекс элемента списка или -1, если элемента в списке нет }
   procedure Remove(const anIndex: _ItemType_);
     {* Удаляет элемент из списка }
   procedure Clear;
     {* Очищает список }
 public
 // public properties
   property Count: IndexType
     read f_Count
     write pm_SetCount;
     {* Количество элементов списка }
   property Capacity: IndexType
     read pm_GetCapacity
     write pm_SetCapacity;
     {* Мощность списка }
   property Items[anIndex: IndexType]: _ItemType_
     read pm_GetItems
     write pm_SetItems;
     default;
     {* Элементы списка. }
   property Empty: Boolean
     read pm_GetEmpty;
     {* Список пустой }
   property First: _ItemType_
     read pm_GetFirst;
     {* Первый элемент списка }
   property Last: _ItemType_
     read pm_GetLast;
     {* Последний элемент списка }
 end;//_List_

{$Else List_imp}

// start class _List_

procedure _List_.ReAllocList(aNewCapacity: IndexType);
//#UC START# *51DEB8770017_51DEB07E03E4_var*
var
 l_Cap : Integer;
 l_Cnt : Integer;
//#UC END# *51DEB8770017_51DEB07E03E4_var*
begin
//#UC START# *51DEB8770017_51DEB07E03E4_impl*
 f_Data.SetSize(aNewCapacity * cItemSize);
 l_Cap := Self.Capacity;
 Assert(l_Cap >= aNewCapacity);
 l_Cnt := f_Count;
 if (l_Cap > l_Cnt) then
  System.FillChar(ItemSlot(l_Cnt)^, (l_Cap - l_Cnt) * cItemSize, 0);
//#UC END# *51DEB8770017_51DEB07E03E4_impl*
end;//_List_.ReAllocList

procedure _List_.CheckIndex(anIndex: IndexType); // can raise EListError
//#UC START# *51DEB95E00BD_51DEB07E03E4_var*

 procedure _Error;
 begin
  raise EListError.CreateFmt(SListIndexError + ' from (%d)', [anIndex, f_Count])
 end;

//#UC END# *51DEB95E00BD_51DEB07E03E4_var*
begin
//#UC START# *51DEB95E00BD_51DEB07E03E4_impl*
 if (anIndex < 0) or (anIndex >= f_Count) then
  _Error;
//#UC END# *51DEB95E00BD_51DEB07E03E4_impl*
end;//_List_.CheckIndex

function _List_.ItemSlot(anIndex: IndexType): PItemType;
//#UC START# *51DEBE2D008A_51DEB07E03E4_var*
//#UC END# *51DEBE2D008A_51DEB07E03E4_var*
begin
//#UC START# *51DEBE2D008A_51DEB07E03E4_impl*
 Result := PItemType(f_Data.AsPointer + anIndex * cItemSize);
 assert(Result <> nil);
//#UC END# *51DEBE2D008A_51DEB07E03E4_impl*
end;//_List_.ItemSlot

function _List_.ExpandSize(aTargetSize: IndexType): Cardinal;
//#UC START# *51DEC11F0058_51DEB07E03E4_var*
const
 cIncrArray : array [0..3] of Integer = (64 * 1024, 1024, 128, 4);
 cMaxForTwice : Integer = 1 * 1024 * 1024;
var
 I : Integer;
//#UC END# *51DEC11F0058_51DEB07E03E4_var*
begin
//#UC START# *51DEC11F0058_51DEB07E03E4_impl*
 Assert(aTargetSize > 0);

 Result := aTargetSize;
 if (Result > cMaxForTwice) then
 // большие массивы не удваиваем а подравниваем под 1мб
  Result := (aTargetSize div cMaxForTwice + 1) * cMaxForTwice
 else
 begin
  for I := 0 to High(cIncrArray) do
   if (aTargetSize > cIncrArray[I]) then
   begin
    Result := (aTargetSize div cIncrArray[I]) * cIncrArray[I] * 2;
    Break;
   end;//aTargetSize > cIncrArray[I]
 end;//Result > cMaxForTwic
//#UC END# *51DEC11F0058_51DEB07E03E4_impl*
end;//_List_.ExpandSize

procedure _List_.CheckSetItem(anIndex: IndexType); // can raise EListError
//#UC START# *51DECAA8035E_51DEB07E03E4_var*
//#UC END# *51DECAA8035E_51DEB07E03E4_var*
begin
//#UC START# *51DECAA8035E_51DEB07E03E4_impl*
 CheckIndex(anIndex);
//#UC END# *51DECAA8035E_51DEB07E03E4_impl*
end;//_List_.CheckSetItem

procedure _List_.DirectInsert(anIndex: IndexType;
  const anItem: _ItemType_);
//#UC START# *51E6A2AA02E4_51DEB07E03E4_var*
var
 l_Cap   : Integer;
 l_Count : Integer;
//#UC END# *51E6A2AA02E4_51DEB07E03E4_var*
begin
//#UC START# *51E6A2AA02E4_51DEB07E03E4_impl*
 l_Count := f_Count;
 l_Cap := Self.Capacity;
 if (l_Count >= l_Cap) then
  ReAllocList(ExpandSize(l_Cap + 1));
 { Make room for the inserted item. }
 Dec(l_Count, anIndex);
 if (l_Count > 0) then
 begin
  MoveItems(anIndex + 1, anIndex + 0, l_Count);
  {$If not defined(l3Items_IsAtomic)}
  FillChar(PMem(ItemSlot(anIndex))^, cItemSize, 0);
  // - это для того, чтобы не оказалось лишней ссылки на строки и/или интерфейсы
  {$IfEnd}
 end;//l_Count > 0
 FillItem(ItemSlot(anIndex)^, anItem);
 Inc(f_Count);
 {$IfDef l3Items_IsAtomic}
 Assert(ItemSlot(anIndex)^ = anItem);
 {$Else  l3Items_IsAtomic}
 {$If (SizeOf(_ItemType_) <= 4) AND not Defined(l3Items_IsProcedured)}
 Assert(ItemSlot(anIndex)^ = anItem);
 {$IfEnd}
 {$EndIf l3Items_IsAtomic}
//#UC END# *51E6A2AA02E4_51DEB07E03E4_impl*
end;//_List_.DirectInsert

procedure _List_.MoveItems(aDst: IndexType;
  aSrc: IndexType;
  aSize: Cardinal);
//#UC START# *51E6A8190252_51DEB07E03E4_var*
type
 PInteger = ^Integer;
var
 l_Sz : Integer;
 l_S  : Integer;
 l_D  : Integer;
 l_B  : PMem;
//#UC END# *51E6A8190252_51DEB07E03E4_var*
begin
//#UC START# *51E6A8190252_51DEB07E03E4_impl*
 if (aSize > 0) then
 begin
  l_B := f_Data.AsPointer;
  l_S := aSrc * cItemSize;
  l_D := aDst * cItemSize;
  l_Sz := aSize * cItemSize;
  if (l_Sz = SizeOf(Integer)) then
  begin
   PInteger(l_B + l_D)^ := PInteger(l_B + l_S)^;
   Exit;
  end//l_Sz = SizeOf(Integer)
  else
   Move((l_B + l_S)^, (l_B + l_D)^, l_Sz);
 end;//aSize > 0
//#UC END# *51E6A8190252_51DEB07E03E4_impl*
end;//_List_.MoveItems

procedure _List_.Delete(anIndex: IndexType); // can raise EListError
//#UC START# *51E6A2660270_51DEB07E03E4_var*
var
 l_P : PItemType;
//#UC END# *51E6A2660270_51DEB07E03E4_var*
begin
//#UC START# *51E6A2660270_51DEB07E03E4_impl*
 CheckIndex(anIndex);
 l_P := ItemSlot(anIndex);
 Dec(f_Count);
 FreeItem(l_P^);
 if (anIndex <> f_Count) then
  MoveItems(anIndex, Succ(anIndex), f_Count-anIndex);
//#UC END# *51E6A2660270_51DEB07E03E4_impl*
end;//_List_.Delete

procedure _List_.Insert(anIndex: IndexType;
  const anItem: _ItemType_); // can raise EListError
//#UC START# *51E6A3140016_51DEB07E03E4_var*

 procedure _Error;
 begin
  raise EListError.CreateFmt(SListIndexError, [anIndex]);
 end;

//#UC END# *51E6A3140016_51DEB07E03E4_var*
begin
//#UC START# *51E6A3140016_51DEB07E03E4_impl*
 if (anIndex < 0) or (anIndex > f_Count) then
  _Error;
 DirectInsert(anIndex, anItem) 
//#UC END# *51E6A3140016_51DEB07E03E4_impl*
end;//_List_.Insert

procedure _List_.Add(const anItem: _ItemType_);
//#UC START# *51E80192036C_51DEB07E03E4_var*
//#UC END# *51E80192036C_51DEB07E03E4_var*
begin
//#UC START# *51E80192036C_51DEB07E03E4_impl*
 DirectInsert(f_Count, anItem);
//#UC END# *51E80192036C_51DEB07E03E4_impl*
end;//_List_.Add

function _List_.IndexOf(const anItem: _ItemType_): IndexType;
//#UC START# *51E801D503C5_51DEB07E03E4_var*
var
 l_Index : IndexType;
//#UC END# *51E801D503C5_51DEB07E03E4_var*
begin
//#UC START# *51E801D503C5_51DEB07E03E4_impl*
 Result := -1;
 // - будем пессимистами
 for l_Index := 0 to f_Count - 1 do
 begin
  if IsSame(ItemSlot(l_Index)^, anItem) then
  begin
   Result := l_Index;
   break;
  end;//IsSame(ItemSlot(l_Index)^, anItem)
 end;//for l_Index
//#UC END# *51E801D503C5_51DEB07E03E4_impl*
end;//_List_.IndexOf

procedure _List_.Remove(const anIndex: _ItemType_);
//#UC START# *51E802290167_51DEB07E03E4_var*
var
 l_Index : IndexType;
//#UC END# *51E802290167_51DEB07E03E4_var*
begin
//#UC START# *51E802290167_51DEB07E03E4_impl*
 l_Index := IndexOf(anIndex);
 if (l_Index >= 0) then
  Delete(l_Index);
//#UC END# *51E802290167_51DEB07E03E4_impl*
end;//_List_.Remove

procedure _List_.Clear;
//#UC START# *51E8026302B4_51DEB07E03E4_var*
//#UC END# *51E8026302B4_51DEB07E03E4_var*
begin
//#UC START# *51E8026302B4_51DEB07E03E4_impl*
 Count := 0;
//#UC END# *51E8026302B4_51DEB07E03E4_impl*
end;//_List_.Clear

procedure _List_.pm_SetCount(aValue: IndexType);
//#UC START# *51DEB1ED0017_51DEB07E03E4set_var*

 procedure SayBadCount(aNewCount: LongInt);
 begin
  raise EListError.CreateFmt(sListIndexError, [aNewCount]);
 end;

var
 l_Ptr   : PItemType;
 {$IfNDef l3Items_IsUnrefcounted}
 l_Index : Integer;
 {$EndIf  l3Items_IsUnrefcounted}
//#UC END# *51DEB1ED0017_51DEB07E03E4set_var*
begin
//#UC START# *51DEB1ED0017_51DEB07E03E4set_impl*
 if (aValue < 0) then
  SayBadCount(aValue);
 if (aValue < f_Count) then
 begin
  l_Ptr := ItemSlot(aValue);
  {$IfDef l3Items_IsUnrefcounted}
  System.FillChar(l_Ptr^, (f_Count - 1 - aValue) * cItemSize, 0);
  {$Else  l3Items_IsUnrefcounted}
  for l_Index := aValue to f_Count - 1 do
  begin
   FreeItem(l_Ptr^);
   Inc(PMem(l_Ptr), cItemSize);
  end;//for i
  {$EndIf  l3Items_IsUnrefcounted}
 end//aValue < f_Count
 else
 if (aValue > Self.Capacity) then
  ReAllocList(ExpandSize(aValue));
 if (f_Count < aValue) then
  System.FillChar(ItemSlot(f_Count)^, (aValue - f_Count) * cItemSize, 0);
 f_Count := aValue;
//#UC END# *51DEB1ED0017_51DEB07E03E4set_impl*
end;//_List_.pm_SetCount

function _List_.pm_GetCapacity: IndexType;
//#UC START# *51DEB20E0130_51DEB07E03E4get_var*
//#UC END# *51DEB20E0130_51DEB07E03E4get_var*
begin
//#UC START# *51DEB20E0130_51DEB07E03E4get_impl*
 Result := f_Data.GetSize div cItemSize;
//#UC END# *51DEB20E0130_51DEB07E03E4get_impl*
end;//_List_.pm_GetCapacity

procedure _List_.pm_SetCapacity(aValue: IndexType);
//#UC START# *51DEB20E0130_51DEB07E03E4set_var*

 procedure SayBadCap(aNewCapacity: IndexType);
 begin
  raise EListError.CreateFmt(sListIndexError, [aNewCapacity]);
 end;

//#UC END# *51DEB20E0130_51DEB07E03E4set_var*
begin
//#UC START# *51DEB20E0130_51DEB07E03E4set_impl*
 if (aValue < 0) then
  SayBadCap(aValue);
 if (pm_GetCapacity <> aValue) then
 begin
  { If the list is shrinking, then update _Count for the smaller size. }
  if (aValue < f_Count) then
   Count := aValue;
  ReAllocList(aValue);
 end;//GetCapacity(Self) <> aValue
//#UC END# *51DEB20E0130_51DEB07E03E4set_impl*
end;//_List_.pm_SetCapacity

function _List_.pm_GetItems(anIndex: IndexType): _ItemType_;
//#UC START# *51DECA1202C5_51DEB07E03E4get_var*
//#UC END# *51DECA1202C5_51DEB07E03E4get_var*
begin
//#UC START# *51DECA1202C5_51DEB07E03E4get_impl*
 CheckIndex(anIndex);
 Result := ItemSlot(anIndex)^;
//#UC END# *51DECA1202C5_51DEB07E03E4get_impl*
end;//_List_.pm_GetItems

procedure _List_.pm_SetItems(anIndex: IndexType; const aValue: _ItemType_);
//#UC START# *51DECA1202C5_51DEB07E03E4set_var*
{$IfNDef l3Items_IsAtomic}
var
 l_P : PItemType;
{$EndIf  l3Items_IsAtomic}
//#UC END# *51DECA1202C5_51DEB07E03E4set_var*
begin
//#UC START# *51DECA1202C5_51DEB07E03E4set_impl*
 CheckSetItem(anIndex);
 {$IfDef l3Items_IsAtomic}
 PItemType(ItemSlot(anIndex))^ := aValue;
 {$Else  l3Items_IsAtomic}
 l_P := PItemType(ItemSlot(anIndex));
 if not IsSame(l_P^, aValue) then
 begin
  FreeItem(l_P^);
  FillItem(l_P^, aValue);
 end;//not IsSame(l_P^, anItem)
 {$EndIf l3Items_IsAtomic}
//#UC END# *51DECA1202C5_51DEB07E03E4set_impl*
end;//_List_.pm_SetItems

function _List_.pm_GetEmpty: Boolean;
//#UC START# *51E7FDAC023D_51DEB07E03E4get_var*
//#UC END# *51E7FDAC023D_51DEB07E03E4get_var*
begin
//#UC START# *51E7FDAC023D_51DEB07E03E4get_impl*
 Result := (Count = 0);
//#UC END# *51E7FDAC023D_51DEB07E03E4get_impl*
end;//_List_.pm_GetEmpty

function _List_.pm_GetFirst: _ItemType_;
//#UC START# *51E8070603AC_51DEB07E03E4get_var*
//#UC END# *51E8070603AC_51DEB07E03E4get_var*
begin
//#UC START# *51E8070603AC_51DEB07E03E4get_impl*
 Result := Items[0];
//#UC END# *51E8070603AC_51DEB07E03E4get_impl*
end;//_List_.pm_GetFirst

function _List_.pm_GetLast: _ItemType_;
//#UC START# *51E8074101B5_51DEB07E03E4get_var*
//#UC END# *51E8074101B5_51DEB07E03E4get_var*
begin
//#UC START# *51E8074101B5_51DEB07E03E4get_impl*
 Result := Items[f_Count - 1];
//#UC END# *51E8074101B5_51DEB07E03E4get_impl*
end;//_List_.pm_GetLast

procedure _List_.Cleanup;
//#UC START# *479731C50290_51DEB07E03E4_var*
//#UC END# *479731C50290_51DEB07E03E4_var*
begin
//#UC START# *479731C50290_51DEB07E03E4_impl*
 Count := 0;
 f_Data.SetSize(0);
 inherited;
//#UC END# *479731C50290_51DEB07E03E4_impl*
end;//_List_.Cleanup

{$EndIf List_imp}

InterfacePtrList.imp.pas:
{$IfNDef InterfacePtrList_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "InterfacePtrList.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::InterfacePtrList
//
// Список УКАЗАТЕЛЕЙ на интерфейсы. Не владеет своими элементами
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define InterfacePtrList_imp}
 _List_Parent_ = _InterfacePtrList_Parent_;
 {$Include ..\SandBox\List.imp.pas}
 _InterfacePtrList_ = {mixin} class(_List_)
  {* Список УКАЗАТЕЛЕЙ на интерфейсы. Не владеет своими элементами }
 end;//_InterfacePtrList_

{$Else InterfacePtrList_imp}

// start class _InterfacePtrList_

procedure FillItem(var thePlace: _ItemType_;
  const aFrom: _ItemType_); forward;

function IsSame(const A: _ItemType_;
  const B: _ItemType_): Boolean; forward;

procedure FreeItem(var thePlace: _ItemType_);
//#UC START# *51DEC20B01D7_51E8098001DC_var*
//#UC END# *51DEC20B01D7_51E8098001DC_var*
begin
//#UC START# *51DEC20B01D7_51E8098001DC_impl*
 !!! Needs to be implemented !!!
//#UC END# *51DEC20B01D7_51E8098001DC_impl*
end;//FreeItem

procedure FillItem(var thePlace: _ItemType_;
  const aFrom: _ItemType_);
//#UC START# *51DECB440087_51E8098001DC_var*
//#UC END# *51DECB440087_51E8098001DC_var*
begin
//#UC START# *51DECB440087_51E8098001DC_impl*
 !!! Needs to be implemented !!!
//#UC END# *51DECB440087_51E8098001DC_impl*
end;//FillItem

function IsSame(const A: _ItemType_;
  const B: _ItemType_): Boolean;
//#UC START# *51DECB820261_51E8098001DC_var*
//#UC END# *51DECB820261_51E8098001DC_var*
begin
//#UC START# *51DECB820261_51E8098001DC_impl*
 !!! Needs to be implemented !!!
//#UC END# *51DECB820261_51E8098001DC_impl*
end;//IsSame

{$Include ..\SandBox\List.imp.pas}


{$EndIf InterfacePtrList_imp}

InterfaceRefList.imp.pas:
{$IfNDef InterfaceRefList_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "InterfaceRefList.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::InterfaceRefList
//
// Список Ссылок на интерфейсы. Владеет своими элементами
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define InterfaceRefList_imp}
 _List_Parent_ = _InterfaceRefList_Parent_;
 {$Include ..\SandBox\List.imp.pas}
 _InterfaceRefList_ = {mixin} class(_List_)
  {* Список Ссылок на интерфейсы. Владеет своими элементами }
 end;//_InterfaceRefList_

{$Else InterfaceRefList_imp}

// start class _InterfaceRefList_

procedure FillItem(var thePlace: _ItemType_;
  const aFrom: _ItemType_); forward;

function IsSame(const A: _ItemType_;
  const B: _ItemType_): Boolean; forward;

procedure FreeItem(var thePlace: _ItemType_);
//#UC START# *51DEC20B01D7_51E809AD001D_var*
//#UC END# *51DEC20B01D7_51E809AD001D_var*
begin
//#UC START# *51DEC20B01D7_51E809AD001D_impl*
 thePlace := nil;
//#UC END# *51DEC20B01D7_51E809AD001D_impl*
end;//FreeItem

procedure FillItem(var thePlace: _ItemType_;
  const aFrom: _ItemType_);
//#UC START# *51DECB440087_51E809AD001D_var*
//#UC END# *51DECB440087_51E809AD001D_var*
begin
//#UC START# *51DECB440087_51E809AD001D_impl*
 thePlace := afrom;
//#UC END# *51DECB440087_51E809AD001D_impl*
end;//FillItem

function IsSame(const A: _ItemType_;
  const B: _ItemType_): Boolean;
//#UC START# *51DECB820261_51E809AD001D_var*
//#UC END# *51DECB820261_51E809AD001D_var*
begin
//#UC START# *51DECB820261_51E809AD001D_impl*
 Result := (A = B);
//#UC END# *51DECB820261_51E809AD001D_impl*
end;//IsSame

{$Include ..\SandBox\List.imp.pas}


{$EndIf InterfaceRefList_imp}

среда, 17 июля 2013 г.

Посоветовали взглянуть. OTL

XXX: я тут с многопоточностью играюсь. занимательно весьма
lulinalex: ох.. вот это для меня - больная тема.. не спец я там совсем...
Sent at 1:07 PM on Wednesday
XXX: я тоже :)
lulinalex: я вообще не понимаю как нормальные люди это программируют...
я щедро assert рассыпаю и вывод в лог
и далее - "методом тыка"...

XXX: взгляни на библиотеку OTL, она сильно все упрощает. для дилетантов вроде меня по крайней мере

http://habrahabr.ru/post/144681/

Глядя на VGScene

"Заметки на полях":

глядя на VGScene
там можно тьюнинговать и поднять производительность
руки только не дойдут
до собственно FM
насколько я видел - матрицы афинных преобразований они создают - даже если они Identity
ну и всё такое - "по мелочи"...
ну и "контролы" надо "виртуализировать" и кешировать
архитектура - хорошая.. реализация - мягко говоря - не очень...
ну и счётчики ссылок тьюнинговать надо

const хотя бы расставить

Зачем нужна "инкапсуляция работы с памятью"

Речь об этом - http://18delphi.blogspot.com/2013/07/1.html

Зачем нужна "инкапсуляция работы с памятью".

Тут будет объяснение.

Пока в двух словах.

Может быть мы захотим использовать не GetMem, а GobalAlloc. Или "маппинг файлов на память".

Или вообще "виртуальную" память собственного "розлива".

По-хорошему надо ещё FillChar и Move "инкапсулировать". Но это я потом сделаю.

Я вообще хочу "оттолкнуться" от контейнеров и их тестов. И перейти к "фреймворкам" и VCM в частности. А потом к "чертежам уровня предприятия".

Чтобы "набрать базу". И на основе её - показать всё от "атомарных контейнеров" ДО UseCase'ов.

Как-то так. Так что "инкапсуляция" работы с памятью и "абстрактные контейнеры" - не самоцель.

А то я тут взялся писать про publisher/subscriber - а там - "блин!" - абстрактные контейнеры.... И скажут - "с чего начинать, какие кнопки жать...." Значит надо начинать с абстракных контейнеров....

Ну и ещё - "инкапсулируя" работу с памятью - мы ЛЕГКО можем собирать РЕАЛЬНУЮ статистику её использования. А не по "TaskManager".

Тонкости implements и почему это не "фасад", а "агрегация в стиле MS"

Тонкости implements и почему это не "фасад", а "агрегация в стиле MS".

Какой там IUnknown.

И как "ловко получить AV".

Пока "в двух словах" FreeAndNil от поля, что implements сделайте. И получите - AV.

понедельник, 15 июля 2013 г.

Из "закромов"

1.

function A: TList;
begin
 Result := nil;
end;

function B: Integer;
begin
 Result := A.Count;
end;

var
 X : Integer;
begin
 X := B;
end;

Вопрос - чему равно X?

2. В чем ошибочен код:

Function A: TList;
Begin
 Reslt := TList.Create;
End;

Function GetPersons(aList: TList);
Begin
 aList.Add(TPerson.Create(‘Иванов’));
 aList.Add(TPerson.Create(‘Петров’));
End;

Var
 l_List : TList;
Begin
 l_List := A;
 GetPersons(L);
End.

3. Дан интерфейс X, как реализовать его на классе - потомке от Y?

В качестве Y использовать - TObject, TComponent и TinterfacedObject.


Условие: Нужно, чтобы число ссылок управляло временем жизни реализующего объекта.

4. Что вы знаете про шаблоны publisher/subscriber и strategy?
На какой механизм Delphi они похожи?.

5. Что такое implements?
Дайте пример поведения счетчика ссылок с implements и без него.


воскресенье, 14 июля 2013 г.

TDD сложнее, чем "просто" тесты

TDD сложнее, чем "просто" тесты. Это надо понимать...

Тесты "по-русски"

: K183337891

 "Открываем НК"
 75 раз ( "Перейти на параграф вниз" )
 "Дождаться переключения вкладок"
 СР
 "Вернуться в текст документа"
 "Выделить {(1)} параграфов"
 "Сравнить выделенный текст текущего редактора с эталоном"
;

K183337891
: K200085315

 : Действия
  "Открываем {(6086112)}"
  "Предварительный просмотр"
  "Нажать {('Esc')}"
  "Выполнить {(@ NOP)} с переключённой базой"
 ;

 ТБ24
 "Выставить форме размеры {(1456 1000)} и {(@ Действия)}"
;

K200085315
: K200085334

 "Открываем {(2008)}"
 "Предварительный просмотр"
 "Дать системе перерисоваться"
 "Нажать {('Esc')}"
 "Выполнить {(@ "Проверить, что удалось перевести фокус в оглавление")} с переключённой базой"
;

K200085334
: K216794957

 ТБ24
 ППР
 "Перевести фокус в поле 'Орган/Источник' в ППР"
 "в поле 'Орган/Источник' ввести {('Правительство России и СССР')}"
 "Выделить текст в поле"
 "Начинаем набирать {('Органы')}"
 "Сравнить абзац текущего редактора с эталоном"
 "Нажать {('Enter')}"
 "Сравнить абзац текущего редактора с эталоном"
 "Нажать Искать"
 "Проверить информацию о списке"
;

K216794957

Ошибки.. ошибки... ошибки...

http://delphi.frantic.im/y-u-no-test-code/

"Вероятно даже буду писать их – если выпадет какой нибудь новый и не спешный проект."

"неспешный проект" - вот это - ОШИБКА! БОЛЬШАЯ ОШИБКА! Тесты надо начинать с проекта "камикадзе"!!!

Если проект - НЕСПЕШНЫЙ, то и ТЕСТЫ - НЕЗАЧЕМ. Тесты нужны для проектов "камикадзе". Чтобы "спать спокойно".

Чужая статья. Запустить тесты и собрать проект – одной командой. Подписываюсь под КАЖДЫМ словом

http://delphi.frantic.im/build-script/

Подписываюсь под КАЖДЫМ словом.

P.S. У на тоже проекты СОБИРАЮТСЯ и ТЕСТИРУЮТСЯ - КАЖДЫЙ день. (Вспомнился эпизод из фильма К-2 с пакистанцем - "Ты как часто это делаешь? (когда он купается в ледяной воде) Ответ - КАЖДЫЙ день...)

суббота, 13 июля 2013 г.

Ещё смешное из VCL

В оконной процедуре там делается кое-что лишнее связанное с отрисовкой пунктов меню - WM_DRAWITEM и WM_MEASUREITEM. Если мы правильно всё поняли. Вот правки:

procedure Tl3Form.WndProc(var Message: TMessage);
  //override;
  {-}
var
  SaveIndex : Integer;
  MenuItem  : TMenuItem;
  DC        : HDC;
begin
  with Message do
    case Msg of
      WM_DRAWITEM:
       if (Message.wParam = 0) then {V - WM_DRAWITEM посылает не только Menu, Message.wParam = 0 это точно Меню}
        with PDrawItemStruct(Message.LParam)^ do
          if (CtlType = ODT_MENU) and Assigned(Menu) then
          begin
            MenuItem := Menu.FindItem(itemID, fkCommand);
            if (MenuItem <> nil) then
            begin
              if (f_Canvas = nil) then
               f_Canvas := TCanvas.Create;
              with f_Canvas do
              try
                SaveIndex := SaveDC(hDC);
                try
                  Handle := hDC;
                  Font := Screen.MenuFont;
                  Menus.DrawMenuItem(MenuItem, f_Canvas, rcItem,
                    TOwnerDrawState(LongRec(itemState).Lo));
                finally
                  Handle := 0;
                  RestoreDC(hDC, SaveIndex)
                end;
              finally
                //Free;
              end;//try..finally
              Exit;
            end;//MenuItem <> nil
          end;//CtlType = ODT_MENU..
      WM_MEASUREITEM:
       if (Message.wParam = 0) then {V - WM_DRAWITEM посылает не только Menu, Message.wParam = 0 это точно Меню}
        with PMeasureItemStruct(Message.LParam)^ do
          if (CtlType = ODT_MENU) and Assigned(Menu) then
          begin
            MenuItem := Menu.FindItem(itemID, fkCommand);
            if (MenuItem <> nil) then
            begin
              DC := GetWindowDC(Handle);
              try
                if (f_Canvas = nil) then
                 f_Canvas := TCanvas.Create;
                with f_Canvas do
                try
                  SaveIndex := SaveDC(DC);
                  try
                    Handle := DC;
                    Font := Screen.MenuFont;
                    TMenuItemAccess(MenuItem).MeasureItem(f_Canvas,
                      Integer(itemWidth), Integer(itemHeight));
                  finally
                    Handle := 0;
                    RestoreDC(DC, SaveIndex);
                  end;
                finally
                  //f_Canvas.Free;
                end;//try..finally
              finally
                ReleaseDC(Handle, DC);
              end;//try..finally
              Exit;
            end;//MenuItem <> nil
          end;//CtlType = ODT_MENU..
    end;//case Msg of
 inherited;
end;

пятница, 12 июля 2013 г.

Обобщаем тесты списков

Предыдущая серия была тут - http://18delphi.blogspot.com/2013/07/blog-post_8789.html

Теперь обобщим приведённые там тесты.

Как обычно.

Модель:

Тут добавился "примесный тест" - ListTest, а все остальные тесты от него - наследуются и определяют тип конкретного списка, который надо тестировать. Этот тест нам сильно пригодится, когда мы будем расширять функциональность контейнеров. Вместе с функциональностью абстрактных контейнеров будем расширять и функциональность примесного теста. Таким образом - КОНКРЕТНЫЕ тесты - "сами" будут расширяться.

Код:

ListTest.imp.pas:
{$IfNDef ListTest_imp}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBoxTest"
// Модуль: "ListTest.imp.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: TestCaseMixIn::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::ListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Define ListTest_imp}
{$If defined(nsTest)}
 _ListTest_ = class(TTestCase)
 published
 // published methods
   procedure DoIt;
   procedure TestTwoLists;
 end;//_ListTest_
{$IfEnd} //nsTest

{$Else ListTest_imp}

{$If defined(nsTest)}

// start class _ListTest_

procedure _ListTest_.DoIt;
//#UC START# *51DEB319037C_51E03FC80111_var*
const
 cCount = 1000;
var
 l_List : _ListType_;
 l_Count : IndexType;
 l_Index : IndexType;
//#UC END# *51DEB319037C_51E03FC80111_var*
begin
//#UC START# *51DEB319037C_51E03FC80111_impl*
 l_List := _ListType_.Create;
 try
  l_List.Count := cCount;
  Check(l_List.Count = cCount);
  Check(l_List.Capacity >= cCount);

  for l_Index := 0 to l_List.Count - 1 do
   Check(l_List[l_Index] = 0);

  l_Count := Random(cCount);
  l_List.Count := l_Count;
  Check(l_List.Count = l_Count, Format('Выделяли %d элементов. Count = %d', [l_Count, l_List.Count]));
  Check(l_List.Capacity >= l_Count, Format('Выделяли %d элементов. Capacity = %d', [l_Count, l_List.Capacity]));

  for l_Index := 0 to l_List.Count - 1 do
   Check(l_List[l_Index] = 0);
   
 finally
  FreeAndNil(l_List);
 end;//try..finally
//#UC END# *51DEB319037C_51E03FC80111_impl*
end;//_ListTest_.DoIt

procedure _ListTest_.TestTwoLists;
//#UC START# *51DED6FC03C1_51E03FC80111_var*
const
 cCount = 1000;
var
 l_A : _ListType_;
 l_B : _ListType_;
 l_Index : IndexType;
 l_Value : _ItemType_;
 l_Max   : _ItemType_;
//#UC END# *51DED6FC03C1_51E03FC80111_var*
begin
//#UC START# *51DED6FC03C1_51E03FC80111_impl*
 l_A := _ListType_.Create;
 try
  l_B := _ListType_.Create;
  try
   l_A.Count := cCount;
   for l_Index := 0 to l_A.Count - 1 do
   begin
    l_Value := Random(1000);
    l_A[l_Index] := l_Value;
    Check(l_A[l_Index] = l_Value);
   end;//for l_Index

   l_B.Count := l_A.Count;
   for l_Index := 0 to l_A.Count - 1 do
   begin
    l_B[l_Index] := l_A[l_Index];
   end;//for l_Index

   for l_Index := 0 to l_A.Count - 1 do
   begin
    Check(l_B[l_Index] = l_A[l_Index]);
   end;//for l_Index
  finally
   FreeAndNil(l_B);
  end;//try..finally
 finally
  FreeAndNil(l_A);
 end;//try..finally
//#UC END# *51DED6FC03C1_51E03FC80111_impl*
end;//_ListTest_.TestTwoLists

{$IfEnd} //nsTest

{$EndIf ListTest_imp}

IntegerListTest.pas:
unit IntegerListTest;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBoxTest"
// Модуль: "IntegerListTest.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::IntegerListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include .\sbtDefine.inc}

interface

{$If defined(nsTest)}
uses
  TestFrameWork,
  IntegerList
  ;
{$IfEnd} //nsTest

{$If defined(nsTest)}
type
 _ListType_ = TIntegerList;
 {$Include .\ListTest.imp.pas}
 TIntegerListTest = class(_ListTest_)
 end;//TIntegerListTest
{$IfEnd} //nsTest

implementation

{$If defined(nsTest)}
uses
  SysUtils
  ;
{$IfEnd} //nsTest

{$If defined(nsTest)}

type _Instance_R_ = TIntegerListTest;
type _ListTest_R_ = TIntegerListTest;

{$Include .\ListTest.imp.pas}


{$IfEnd} //nsTest

initialization
 TestFramework.RegisterTest(TIntegerListTest.Suite);
end.

ByteListTest.pas:
unit ByteList;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBox"
// Модуль: "ByteList.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TByteList
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include .\sbDefine.inc}

interface

uses
  Refcounted,
  Classes,
  l3PtrLoc
  ;

type
 _ItemType_ = Byte;
 _AtomicList_Parent_ = TRefcounted;
 {$Include .\AtomicList.imp.pas}
 TByteList = class(_AtomicList_)
 end;//TByteList

implementation

uses
  RTLConsts,
  l3MemorySizeUtils
  ;

type _Instance_R_ = TByteList;
type _AtomicList_R_ = TByteList;

{$Include .\AtomicList.imp.pas}

end.

Int64ListTest.pas:
unit Int64ListTest;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "SandBoxTest"
// Модуль: "Int64ListTest.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::Int64ListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{$Include .\sbtDefine.inc}

interface

{$If defined(nsTest)}
uses
  TestFrameWork,
  Int64List
  ;
{$IfEnd} //nsTest

{$If defined(nsTest)}
type
 _ListType_ = TInt64List;
 {$Include .\ListTest.imp.pas}
 TInt64ListTest = class(_ListTest_)
 end;//TInt64ListTest
{$IfEnd} //nsTest

implementation

{$If defined(nsTest)}
uses
  SysUtils
  ;
{$IfEnd} //nsTest

{$If defined(nsTest)}

type _Instance_R_ = TInt64ListTest;
type _ListTest_R_ = TInt64ListTest;

{$Include .\ListTest.imp.pas}


{$IfEnd} //nsTest

initialization
 TestFramework.RegisterTest(TInt64ListTest.Suite);
end.

Код тут - http://sourceforge.net/p/rumtmarc/code-0/19/tree/trunk/Blogger/SandBox и http://sourceforge.net/p/rumtmarc/code-0/19/tree/trunk/Blogger/SandBoxTest