Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Вопросы по Delphi (до версии 2009) - часть 5

Автор: AviDen
Дата сообщения: 08.04.2010 10:16
Odysseos
Цитата:
почему Вы считаете, что WinAPI-функция поиска конца PWideChar-строки (lstrlenW) будет быстрей, чем просто проход в цикле по всем символам

Ну если бы я на месте M$ писал lstrlenW, я бы использовал процессорную инструкцию repnz scansw (всего одну!!), которая будет, скажем так, слегка шустрее, чем цикл по символам Кстати, подозреваю, что так она и сделана.


Цитата:
нафига извращаться с именно юникодными версиями функций, если можно русские (да хоть китайские!) строковые значения хранить в обычном ANSI ini закодированными в UTF8

Я так скажу - лично мне проще пользоваться "родным" для винды типом WideString (кодировка UCS16-LE), чем utf8. Ну не нравятся мне типы с переменной длиной одного символа, не нравятся! Ну, а уж Ansi и прочее неюникодное фуфло - это вообще позавчерашний день.

Добавлено:
Maks150988

Цитата:
Оболдеть, кажется такая простая задача, а над решением можно долго биться.

Добро пожаловать в мир WinApi.
Автор: Odysseos
Дата сообщения: 08.04.2010 11:00
AviDen

Ну если бы я на месте M$ писал lstrlenW, я бы использовал процессорную инструкцию repnz scansw (всего одну!!), которая будет, скажем так, слегка шустрее, чем цикл по символам Кстати, подозреваю, что так она и сделана.

Я Вас расстрою - но lstrlenW работает вот так:

...
7655A51F mov cx,[eax]
7655A522 inc eax
7655A523 inc eax
7655A524 test cx,cx
7655A527 jnz $7655a51f
...

И это еще не считая разной подготовительной работы и вообще самого call'а со срывом конвейера (тем более, что внутри есть еще один call).


Я так скажу - лично мне проще пользоваться "родным" для винды типом WideString (кодировка UCS16-LE), чем utf8. Ну не нравятся мне типы с переменной длиной одного символа, не нравятся! Ну, а уж Ansi и прочее неюникодное фуфло - это вообще позавчерашний день.

Delphi 2009+ - Ваш выбор в этом случае.

...А насчет WideString (BSTR, если уж на то пошло) - Вы в курсе, что он "малость" менее оптимален, чем "родные" строки Delphi? В том смысле, что он не reference-counted, и при всех его присваиваниях-передачах Delphi каждый раз создает точную копию строки.

Добавлено:
Maks150988

Ну желательно меньшим кодом "отделаться"

Это как? Чтоб один компонент на форму бросить - и порядок, заработало?


Не проблема, в цикле тогда надо увеличивать буфер и сравнивать значение, а не меньше ли возврат на 2, пока не достигнем нужного размера.

Мой код именно это и делает.


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

В моем коде буфер можно задать хоть в один символ - он все равно прочитает _все_ (пусть и не очень быстро). А Ваш - не больше размера буфера.
Автор: AviDen
Дата сообщения: 08.04.2010 11:22
Odysseos, меня это не расстраивает )) я всегда пользую length(), который просто читает длину строки из нулевого символа (кстати, чистые pchar- и pwidechar- данные мне тоже не особо нравятся по причине невозможности быстро узнать длину строки, не считая символы). Да и ваще, работа со строками c-style - это жуткий отстой и гемор, сочувствую сишникам, не имеющих простых и удобных string и widestring типов.

Про отсутствие reference-countring у широких строк, понятное дело, знаю, однако это не проблема. Если грамотно подходить к написанию кода (держа в памяти тот факт, что строки копируются всегда при передаче по значению или присвоении), то в 99% случаев лишних операций с памятью можно избежать. Как минимум, объявляя все widestring-параметры в функциях и процедурах как const или var (тогда они передаются по ссылке без копирования). Ну и ещё есть пара трюков в запасе. А остальной 1% с лихвой компенсируется удобством использования и универсальностью на многие годы вперёд.

P.S. Про D2009 пока только мечтаю, к сожалению, проект ещё не скоро дойдёт до состояния готовности к апгрейду с d7 на что-то посвежее... ((

Добавлено:
P.P.S. А чего это call должен срывать конвейер? Я конечно в этом не дока, но это же не условный переход (да и те проц умеет предсказывать, плюс он в любом случае на всякий случай конвейеризует код по обоим веткам, если я не ошибаюсь).
Автор: Odysseos
Дата сообщения: 08.04.2010 11:37
AviDen

я всегда пользую length()

В данной задаче - чтении и разборе списка всех секций из ini-файла - приходится работать именно с C-строками, последователно расположенными в буфере и разеленными #0. Их так WinAPI возвращает, и ничего с этим не поделать.


А чего это call должен срывать конвейер? Я конечно в этом не дока, но это же не условный переход

Не обязательно сорвет. Но вероятность есть, особенно учитывая несколько условных переходов внутри call'а, еще один внутренний call и условный возврат из него.
Автор: AviDen
Дата сообщения: 08.04.2010 11:57
Да мы вообще для проекта написали свой widestring-аналог TIniFile и не паримся... А то винапишные танцы с бубном по каждому мелкому поводу как-то не прельщают.
Автор: YuriyRR
Дата сообщения: 08.04.2010 15:51
Odysseos

Цитата:
Я Вас расстрою - но lstrlenW работает вот так

Угарно!. 5 баллов.
Автор: Maks150988
Дата сообщения: 08.04.2010 18:50
Да ладно вам блин, а то щас начнется бурление коричневого вещества, такое бурное обсуждение.
У меня вот такой вопрос, годится ли сранивание WideString тупо через знак равенства?

Код: if (wstr1 = wstr2) then blablabla
Автор: Odysseos
Дата сообщения: 08.04.2010 19:31
Maks150988

Оператор "=" сравнивает строки с учетом регистра. А в описании lstrcmpi ясно указано:


Цитата:

Compares two character strings. The comparison is not case-sensitive.


Если хотите wide-строки сравнивать "по-дельфийски" - то WideSameText для сравнения без учета регистра, и WideSameStr - c учетом (полный аналог "=").

Также - WideCompareText и WideCompareStr сравнивают wide-строки (без учета регистра и с учетом соответственно) на меньше/больше/равно.
Автор: Maks150988
Дата сообщения: 08.04.2010 21:22
Odysseos
Так в том то и прикол что регистр совпадал. Да даже просто начал строки с цифрами сверять, а оно не совпадало, ну ладно бы текст еще.
Автор: Odysseos
Дата сообщения: 08.04.2010 23:15
Maks150988

Быть не может. Вы где-то ошиблись, видимо. Только что проверил (удостоверится, що з глузду не зъихав), Delphi 2007:


Код:
procedure TForm1.FormCreate(Sender: TObject);
var
s1, s2: WideString;
begin
s1 := 'аБв';
s2 := 'аБв';

if s1 = s2 then
Caption := '!';
end;
Автор: Maks150988
Дата сообщения: 09.04.2010 07:58
Odysseos

Вот моя программа: Ссылка

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

Код находится в модуле D_FinsWind.pas:

Код: if (lstrcmpiW(@ObjectName[1], @pszEntry[1]) = 0) then
Автор: AviDen
Дата сообщения: 09.04.2010 09:07
Maks150988, я код по ссылке не смотрел (времени нет), но исходя из общепринятого стиля именования переменных (ведь Вы же всё из каких-то сишных/апишных примеров берёте, как я вижу) pszEntry - это указатель на некое число (скорее всего размер чего-либо). Сравнивать имя некоторого объекта с указателем на число - ну, сами понимаете...

А вообще, строки обычным оператором сравнения сравнивать нельзя никогда, исключительно функциями WideSameText/WideSameStr/WideCompareText/WideCompareStr, как и написал Odysseos. Для Ansi-строк также есть соотв. аналоги с префиксом Ansi.
Автор: Maks150988
Дата сообщения: 09.04.2010 10:38
AviDen
ObjectName и pszEntry это WideString.

Ну теперь буду знать, просто практически всегда на форумах попадаются такие вот сравнения, я как-то не задумывался об этом.

Odysseos

Не знаю как насчет быстроты вашего рабочего кода, но я пока сделал так, впринципе если я ничего не попутал в коде, размер буфера будет увеличиваться до тех пор, пока разница будет равна 2.


Код: function IniFileProfileExistsW(pszFileName, pszAppName: WideString): Boolean;
var
pszBuf : WideString;
workBuf: LPWSTR;
nSize : DWORD;
dwRet : DWORD;
begin

Result := FALSE;

nSize := MAX_PATH;
dwRet := 0;
SetLength(pszBuf, nSize);

repeat
Inc(nSize);
SetLength(pszBuf, nSize);
dwRet := GetPrivateProfileSectionNamesW(LPWSTR(pszBuf), nSize, LPWSTR(pszFileName));
until
(nSize - dwRet) <> 2;

workBuf := LPWSTR(pszBuf);

while (workBuf <> nil) and (workBuf^ <> #0) do
begin
if (lstrcmpiW(LPWSTR(pszAppName), workBuf) = 0) then
begin
Result := TRUE;
Break;
end;
Inc(workBuf, lstrlenW(workBuf) + 1);
end;

end;
Автор: Odysseos
Дата сообщения: 09.04.2010 15:31
Maks150988



Код:
Inc(nSize);
SetLength(pszBuf, nSize);
dwRet := GetPrivateProfileSectionNamesW(LPWSTR(pszBuf), nSize, LPWSTR(pszFileName));
Автор: apnss
Дата сообщения: 09.04.2010 15:34
AviDen

Цитата:
Да мы вообще для проекта написали свой widestring-аналог TIniFile и не паримся... А то винапишные танцы с бубном по каждому мелкому поводу как-то не прельщают.


на д2010 свой компонент не тестили?

я тут был пару своих проектиков решил портануть. в них как-раз используются ДЛЛки с обработкой widestring'ов. вроде все работает но память утекает непонятно куда . пришлось на время перенос отложить.

Автор: AviDen
Дата сообщения: 09.04.2010 16:37
apnss, нет, у нас проект на D7 и будет на ней ещё оооочень долго
Для борьбы с утечками FastMM используете? Попробуйте, крайне рекомендую.
Автор: Maks150988
Дата сообщения: 09.04.2010 16:54
Odysseos
А я не знаю как оптимальнее, у вас тоже цикл идет, только вначале вы выделяете буфер длинной со строку + BUF_SIZE. Можно от балды сразу 65535 ухнуть.
Автор: apnss
Дата сообщения: 09.04.2010 17:45
AviDen

FastMM юзаем, но он кстати толком ничего не показывает. ДЛЛки шли отдельным проектом , там активно юзаеются калбэки и ракировки апликейшина.

скорее всего по Д2010 прийдется полностью менять концепцию и переписывать все с нуля .

Автор: Odysseos
Дата сообщения: 09.04.2010 18:11
Maks150988

вначале вы выделяете буфер длинной со строку + BUF_SIZE

Я его не вначале выделяю длиной со строку, я перед каждой попыткой чтения увеличиваю буфер на BUF_SIZE. То есть - первый раз пытаюсь прочитать BUF_SIZE, не хватило - пытаюсь прочитать 2 * BUF_SIZE, не получилось - 3 * BUF_SIZE, и так пока не влезет.

Можно вообще на каждом шаге удваивать текущую длину буфера - это еще быстрее будет, но затратнее по памяти - тут надо баланс искать.
Автор: AviDen
Дата сообщения: 09.04.2010 18:34
apnss, гм, что значит - толком ничего не показывает? По каждой утечке в логе отражён стек-трейс до строки кода, где эта область памяти была выделена, с именами модулей/функций/процедур и номерами строк + содержание этого самого блока. И то, и другое в 90% случаев помогает определить реальный источник утечки.
Автор: Maks150988
Дата сообщения: 09.04.2010 18:37
Odysseos
Да, я согласен с вами, что лучше удваивать длину буфера при каждом шаге, но в моем случае с лихвой хватает и текущей длины, так что все за один присест прочитается.

Тогда цикл такой, чтобы уж наверняка.

Код: repeat
dwRet := GetPrivateProfileSectionNamesW(LPWSTR(pszBuf), nSize, LPWSTR(pszFileName));
if ((nSize - dwRet) = 2) then
begin
Inc(nSize, MAX_PATH);
SetLength(pszBuf, nSize);
end;
until
(nSize - dwRet) <> 2;
Автор: apnss
Дата сообщения: 09.04.2010 19:30
AviDen

я знаю как юзать FastMM в фулдебаг режиме


Цитата:
apnss, гм, что значит - толком ничего не показывает?


то и значит - лог пустой (я имею в виду утечки), но при работе приложения скомпиленного на д2010 за полдня "уходит" 500метров ОЗУ в никуда.

при работе приложения скомпиленного в д2007 такого не наблюдается - прога "крутится" неделями с теми же ДЛЛками.

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

вот такие пироги

ПыСы: нада завязывать д2010 тут офтоп
Автор: Bonivur
Дата сообщения: 10.04.2010 22:27
Odysseos
Меня тут долго не было... Проблемы-с. Продолжая дискуссию о нахождении всех возможных вариантов определенного аккорда на грифе гитары. Ограничения простые - выбирается аккорд, допустим Dm (ре-минор), находятся ноты, входящие в данный аккорд - F(фа), A(ля), С (до). Это все легко. Вот дальше начинаются сложности. Надо найти все возможные сочетания этих трех нот на грифе гитары (то есть задействовано от 3-ех до 6-ти струн). Бас роли не играет. Ноты могут идти в любом произвольном порядке. Аккорд останется все равно тем же. Допустимы промежуточные незвучащие струны, так же как и наоборот, открытые струны. Главное, чтобы не звучали ноты НЕ входящие в аккорд. Невозможно, также, нахождение двух нот на ОДНОЙ струне в готовом аккорде. На гитаре всегда будет звучать только одна нота на каждой отдельно взятой струне. То есть, 1 струна <= 1 нота, но не обязательно использовать все струны. Допустимы удвоения нот в любых вариантах - FFAADD, DAAF, DFAFA и.т.д. Предел для растяжки пальцев можно взять в 4 лада (это не принципиально). Получаем участок грифа гитары 6 (струн) на 4 (лада) для каждой позиции (позиция - положение указательного пальца при взятии аккорда). Вот для этого участка надо найти все возможные варианты построения аккорда (в данном примере - Dm, ре-минор). Надо еще помнить, что нужны и те варианты, когда нота подходящая есть, но возможен вариант и с ее пропуском, так как можно ее получить на другой струне.
Преимущества в басах (допустим для тоники - Ре) нет. Задача не абстрактная. Если найду механизм как это осуществить, то все остальное уже довольно просто. Залез даже в теорию графов с их обходом, но что-то очень сложно. Тут другая идея - ведь все возможные аккорды можно описать схемой вида - 00 01 00 02 03 XX (аккорд С). У меня уже есть программа, в которой пользователь проставляя ноты аккорда (точки на грифе) узнает, что это за тип аккорда, к тому же автоматом пишется эта буквенно цифровая схема в одну строку. Так вот идея в том чтобы перебрать все варианты в каждом элементе строки (от 00 до 04) пока программа не выдаст, что это аккорд Dm. Но как организовать такой цикл? И сущает что будет слишком много "холостого" хода. Ведь найти ноты на грифе которые заведомо соответствуют нотам аккорда не сложно, хочется "плясать" от этого. Вообщем, не знаю как подступиться. Если кого интересует проблема - пишите на мыло тоже. Буду рад если сможете как-то помочь.
Автор: Odysseos
Дата сообщения: 10.04.2010 23:48
Bonivur

Мдя... Чего уж сложного-то?

[more]

Код:
const
tOctave = 0;

tC = tOctave + 0;
tCs = tOctave + 1;
tD = tOctave + 2;
TDs = tOctave + 3;
tE = tOctave + 4;
tF = tOctave + 5;
tFs = tOctave + 6;
tG = tOctave + 7;
tGs = tOctave + 8;
tA = tOctave + 9;
tB = tOctave + 10;
tH = tOctave + 11;

type
TTune = tC .. tH;
TTunes = set of TTune;
TChord = array [1 .. 6] of Integer;

const
Guitar: array [1 .. 6] of TTune = (tE, tH, tG, tD, tA, tE);

var
tunes_to_find, tunes_not_found_yet: TTunes;
chord: TChord;
i, j, pos, dist: Integer;
tune: TTune;
begin
// "обнуляем" аккорд
for i := Low(chord) to High(chord) do
chord[i] := - 1;

// задаем начальные значения
// позиция
pos := 0;
// расстояние
dist := 4;
// аккорд для поиска
tunes_to_find := [tD, tF, tA];

tunes_not_found_yet := tunes_to_find;

for i := Low(chord) to High(chord) do begin
first_tune_pos := - 1;

for j := pos to pos + dist do begin
tune := (Guitar[i] + j) mod 12;
if [tune] * tunes_to_find = [tune] then
if (tunes_not_found_yet = []) or
([tune] * tunes_not_found_yet = [tune])
then begin
tunes_not_found_yet := tunes_not_found_yet - [tune];

chord[i] := j;

Break;
end
else
if first_tune_pos < 0 then
first_tune_pos := j;
end;

if (chord[i] < 0) and (first_tune_pos >= 0) then
chord[i] := first_tune_pos;
end;

// в массиве chords - позиции нот на каждой из струн
end;
Автор: EugeneBoss3
Дата сообщения: 11.04.2010 02:27
Коллеги, помогите составить хранимую процедуру для Firebird. Нужно чтобы сервер возвращал набор данных при изменении значения символьного поля в главной таблице у связанной с ней по символьному полю. Использую Delphi 2007 и IBDAC.
Автор: Odysseos
Дата сообщения: 11.04.2010 02:57
EugeneBoss3

Во-первых - для Firebird'а есть отдельная тема.

А во-вторых - объясните, плз, понятней.
Автор: svs123456789
Дата сообщения: 11.04.2010 07:22
кто-нибудь имеет опыт создания некоего простого аналога векторного редактора или автокада или скорее визио...
надо визуализировать план помещений (возможно даже в 3d) с движущимися объектами...
или копать в сторону opengl или directx или может даже xna ?
или искать библиотеки под delphi (желательно бесплатные) ?
Автор: aspis
Дата сообщения: 11.04.2010 08:45
svs123456789
Тоже возникала аналогичная задача визуализации плана. За основу взял Контейнер визуальных объектов
Автор: Frodo_Torbins
Дата сообщения: 11.04.2010 10:15
apnss
Проследите, чтобы и библиотеки и приложение использовали общий менеджер памяти.
Автор: Bonivur
Дата сообщения: 11.04.2010 11:07
Odysseos
Спасибо за подробный ответ, но найти аккорд перебором "пострунно" вверх - это конечно не составляет проблем и я уже давно сделал. Вопрос как найти аккорды если допустим, 1-ая струна вообще не звучит, Далее - 2-ая струна на 3-ем ладу (РЕ), 3-яя струна на 2-ом ладу (ЛЯ), далее 4-ая и 5-ая струна пропускаем, 6-ая струна 1-ый лад (ФА). Это тоже аккорд Dm. То есть можно пропустить 4-ую и 5-ую струны, хотя на них и есть требуемые ноты, просто чтобы найти все варианты в 1 (одной!) позиции то есть в пределах 4-ех ладов. То есть chord может состоять и из 3 и из 4, 5 нот. К примеру, для нот аккорда tunes_to_find := [tFs, tE, tGs, tH] находится далеко не самый удобный вариант. Логичнее было бы найти Фа-диез на 1-ой струне, Ми - на 4-ой струне, Соль-диез на 3-ей и Си на 2-ой открытой.

Страницы: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768

Предыдущая тема: Clipper 5


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.