Страница 1 из 1
измена размера буфера &STRING
Добавлено: 23 Сентябрь 2006, 13:49
StillZero
Здравствуйте, всем.
Есть две похожие задачи.
Есть буфер данных. Выглядит так:
Код: Выделить всё
buf &STRING
buf_len LONG
code
buf &= new STRING(100)
buf_len = 100
Во-первых, необходимо увеличить буфер на известное количество байт.
Примерно так:
Код: Выделить всё
memcpy(address(buf)+100,address(add_buf),10) ! дописываем к буферу 10 байт
buf_len = 110
Во-вторых, необходимо сдвинуть и уменьшить буфер на известное кол-во байт:
Код: Выделить всё
buf &= (address(buf) + 17) ! сдвигаем на 17 байт
buf_len -= 17
Подозреваю, что при уничтожении буфера я получи лики, так как компилятор не знает buf_len.
На данный момент, выхожу из ситуации так:
Код: Выделить всё
tmp_buf &STRING
...
code
...
tmp_buf &= new STRING(buf_len)
memcpy(address(tmp_buf),address(buf),buf_len) ! сохранили во временном буфере
dispose(buf)
buf &= new STRING(buf_len+10) ! создали по новой необходимой длины
memcpy(address(buf),address(tmp_buf),buf_len) ! вернули из временного буфера
memcpy(address(buf)+buf_len,address(add_buf),10) ! добавили новые данные
dispose(tmp_buf)
С уменьшением буфера поступаю аналогично.
Решение это не нравится. IMHO кажется слишком долго это все будет. Тем более, что
буфер может быть до 10МБ (примерно) и выполнятся операции будут достаточно периодично.
Необходимо другое правильное

решение.
Спасибо.
ЗЫ
перешлите плиз письмо в ClaList, у меня проблемы с мылом
Добавлено: 24 Сентябрь 2006, 16:33
Олег
Есть два варианта:
- стандартный алгоритм решения подобных задач через использование функции ReAllocMem. Для этого достаточно в MAP-секции задекларировать соответствующую функцию RTL Клариона:
Код: Выделить всё
MAP
AllocMem(UNSIGNED _Size),ULONG,NAME('Cla$NewMemZ'),DLL(dll_mode)
ReAllocMem(ULONG _MemAddr,UNSIGNED _NewSize),ULONG,NAME('_realloc'),DLL(dll_mode)
FreeMem(ULONG _MemAddr),NAME('_free'),DLL(dll_mode)
END
buf ULONG
buf_len LONG
Code
...
buf_len = 100
buf = AllocMem(buf_len) ! аналог New CSTRING(100)
...
buf_len += 10
buf = ReAllocMem(buf,buf_len)
...
buf_len -= 17
buf = ReAllocMem(buf,buf_len)
...
FreeMem(buf)
Как частный случай данного варианта, можно использовать класс DynStr Клариона - к нему можно "достучаться" в C5/55, а в C6x он вообще вынесен на уровень разработчика и доступен как обычный библиотечный класс. При его использовании можно получить некоторое ускорение работы за счет того, что выделяется буфер несколько большего размера, чем запрошено и при "урезании" остаток буфера не освобождается - получаем более быструю отработку операций увеличения размера буфера.
- довольно часто можно встретить самописные менеджеры памяти, когда в начале работы с динамическим буфером выделяется заведомо большой размер буфера, чем может понадобиться. Дальнейшая работа уже идет внутри этого выделенного буфера - т.е. есть первоначальный адрес буфера, его реальный размер, текущий адрес используемого подбуфера и его текущий размер. Если "обернуть" этот алгоритм в класс, то получится что-то типа уже упоминавшегося DynStr. Плюс - быстрая отработка операций увеличения/уменьшения размера буфера (нет необходимости переноса текущего содержимого буфера в новый буфер). Минус - неэфективное использование памяти. Особенно при большом кол-ве подобных обьектов.
Добавлено: 07 Октябрь 2006, 14:23
StillZero
жаль, что не сразу этим занялся, но лучше уж поздно...и поэтому возвращаюсь к напечатанному
с увеличением буфера все понятно
проблемы с уменьшением
дело в том, что в буфере находятся данные, я читаю их из буфера, а после того как прочитал, хочу уменьшить буфер на размер прочитанных байт, а в буфере должны остаться не прочитанные данные, если на примере то это примерно так:
buf = 'ТестовыеДанные'
читаю данные в очередь:
Q.Buf = 'Тестовые'
add(Q)
теперь хочу уменьшить буфер и чтобы в нем осталось так:
buf = 'Данные'
т.е. если делать _realloc для уменьшения буфер, то думаю, что обрежет то начиная с конца, т.е. получится buf = 'Тестов'
вопрос: как обойтись без промежуточного копирования данных?
Добавлено: 07 Октябрь 2006, 21:12
Дед Пахом
Ну как в сях - имеешь _указатель_ на начало буфера, прочитал - указатель передвинул на длину прочитанного. А динамически играться с выделением/освобождением памяти, имхо, себе дороже.
Добавлено: 08 Октябрь 2006, 5:43
StillZero
Ну как в сях - имеешь _указатель_ на начало буфера, прочитал - указатель передвинул на длину прочитанного.
изначально так и собирался делать, но мне кажется что при уничтожении буфера я получу лики, а если я выберу вообще весь буфер, т.е. его длина станет равной нулю, то непонятно что вообще уничтожать
на данный момент использую связку memmove + realloc
memmove - это аналог memcpy, только корректно разруливает перекрывающиеся буфера, т.е. допустим надо уменьшить буфер на 1 байт:
Код: Выделить всё
memmove(buf,buf+1,buf_len-1) ! сдвигаем буфер на 1 байт влево
buf = realloc(buf,buf_len-1) ! изменяем размер буфера
buf_len -= 1
Добавлено: 08 Октябрь 2006, 8:03
Дед Пахом
я вообще-то имел в виду несколько другое:
Код: Выделить всё
указатель = адрес(начало_буфера)
пока указатель <= адрес(конец_буфера)
len = сколько надо
читаем указатель[1 : len]
указатель += len
endпока
dispose(весь буфер целиком за раз)
Добавлено: 09 Октябрь 2006, 10:05
Andrew™
StillZero писал(а):Ну как в сях - имеешь _указатель_ на начало буфера, прочитал - указатель передвинул на длину прочитанного.
изначально так и собирался делать, но мне кажется что при уничтожении буфера я получу лики, а если я выберу вообще весь буфер, т.е. его длина станет равной нулю, то непонятно что вообще уничтожать
на данный момент использую связку memmove + realloc
memmove - это аналог memcpy, только корректно разруливает перекрывающиеся буфера, т.е. допустим надо уменьшить буфер на 1 байт:
Код: Выделить всё
memmove(buf,buf+1,buf_len-1) ! сдвигаем буфер на 1 байт влево
buf = realloc(buf,buf_len-1) ! изменяем размер буфера
buf_len -= 1
Изобретаешь велосипед, на сколько я знаю ты пользователь моей библиотеки и у тебя есть объект типа MAVString
Код: Выделить всё
tmp MAVString
CODE
tmp.Reset(tmp.S[2 : tmp.Pos])
и всё - твои два действия сводятся к одному
Добавлено: 09 Октябрь 2006, 10:24
Admin
А если без использования MAV нужно применить данную методу ...
Может быть откроешь код MAVString?

Добавлено: 09 Октябрь 2006, 10:30
Andrew™
Admin писал(а):А если без использования MAV нужно применить данную методу ...
Может быть откроешь код MAVString?

как говорится No Problem, ещё хочу заметить, много тестировал
realloc alloc, APIшные аналоги,
всё равно NEW DISPOSE NEW работает быстрее
http://mavcla.arsis.ru/Download/MAVString.rar
ЗЫ
ты получил моё сегодняшнее письмо, если да, То какие результаты
Добавлено: 09 Октябрь 2006, 11:00
Admin
Результаты супер. Глюков нет!
В течении недели думаю если что то осталось выяснится ...
Добавлено: 09 Октябрь 2006, 11:37
Andrew™
Admin писал(а):Результаты супер. Глюков нет!
В течении недели думаю если что то осталось выяснится ...
ну тады закрывай ветку "Опять глюки!". не люблю это слово
кстати, попробовал что то аналогичное в выходные состряпать и на FILE,DRIVER('ODBC') и на FILE,DRIVER('MSSQL') там вааще оказывается задача твоя невыполнима, прога ведёт себя непредказуемо, либо виснет, либо кричит "соединение занято другим открытым HTMT"
Добавлено: 09 Октябрь 2006, 13:12
Admin
Я рад. Еще один плюс тебе на грудь

))
Добавлено: 10 Октябрь 2006, 9:20
Леонид
Andrew™ писал(а):[Изобретаешь велосипед, на сколько я знаю ты пользователь моей библиотеки и у тебя есть объект типа MAVString
Код: Выделить всё
tmp MAVString
CODE
tmp.Reset(tmp.S[2 : tmp.Pos])
и всё - твои два действия сводятся к одному
Андрей, а малюсенькое описание можешь кинуть по методам Reset, Insert...?
Добавлено: 11 Октябрь 2006, 9:41
Andrew™
Леонид писал(а):Andrew™ писал(а):[Изобретаешь велосипед, на сколько я знаю ты пользователь моей библиотеки и у тебя есть объект типа MAVString
Код: Выделить всё
tmp MAVString
CODE
tmp.Reset(tmp.S[2 : tmp.Pos])
и всё - твои два действия сводятся к одному
Андрей, а малюсенькое описание можешь кинуть по методам Reset, Insert...?
надо на самом деле всего два метода: .Reset и .AppendString, .Insert необходим для работы с бинарной не текстовой инфо.
Reset - сбрасывает динамический буфер в НУЛЬ если параметр отсутствует или в размер этого параметра + волшебный ДЕЛЬТА которая хранится в .Size, для чего это, а чтобы на каждый .AppendString не делать DISPOSE NEW, может и хватить существующего запаса.
Код: Выделить всё
tmp MAVString
CODE
tmp.Reset('Hello!!!')
MESSAGE(tmp.S[1 : tmp.Pos]) - Hello!!!
tmp.AppendString(' Clarion')
MESSAGE(tmp.S[1 : tmp.Pos]) - Hello!!! Clarion
tmp.Reset('Clarion')
MESSAGE(tmp.S[1 : tmp.Pos]) - Clarion
tmp.Reset()
MESSAGE(tmp.Pos) - 0
почти всегдя юзаю MAVString при работе со строками, голова не болит о переполнении т к вроде ошибки и не будет, но инфо потеряется.