измена размера буфера &STRING

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Аватара пользователя
StillZero
Ветеран
Сообщения: 458
Зарегистрирован: 06 Июль 2005, 2:17
Откуда: Хабаровск
Поблагодарили: 1 раз
Контактная информация:

измена размера буфера &STRING

Сообщение 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, у меня проблемы с мылом
Аватара пользователя
Олег
Ветеран движения
Сообщения: 122
Зарегистрирован: 16 Июль 2005, 2:35
Откуда: Москва
Контактная информация:

Сообщение Олег »

Есть два варианта:
- стандартный алгоритм решения подобных задач через использование функции 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. Плюс - быстрая отработка операций увеличения/уменьшения размера буфера (нет необходимости переноса текущего содержимого буфера в новый буфер). Минус - неэфективное использование памяти. Особенно при большом кол-ве подобных обьектов.
Аватара пользователя
StillZero
Ветеран
Сообщения: 458
Зарегистрирован: 06 Июль 2005, 2:17
Откуда: Хабаровск
Поблагодарили: 1 раз
Контактная информация:

Сообщение StillZero »

жаль, что не сразу этим занялся, но лучше уж поздно...и поэтому возвращаюсь к напечатанному

с увеличением буфера все понятно

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

buf = 'ТестовыеДанные'
читаю данные в очередь:
Q.Buf = 'Тестовые'
add(Q)
теперь хочу уменьшить буфер и чтобы в нем осталось так:
buf = 'Данные'

т.е. если делать _realloc для уменьшения буфер, то думаю, что обрежет то начиная с конца, т.е. получится buf = 'Тестов'

вопрос: как обойтись без промежуточного копирования данных?
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3289
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 49 раз
Контактная информация:

Сообщение Дед Пахом »

Ну как в сях - имеешь _указатель_ на начало буфера, прочитал - указатель передвинул на длину прочитанного. А динамически играться с выделением/освобождением памяти, имхо, себе дороже.
С уважением, ДП
Аватара пользователя
StillZero
Ветеран
Сообщения: 458
Зарегистрирован: 06 Июль 2005, 2:17
Откуда: Хабаровск
Поблагодарили: 1 раз
Контактная информация:

Сообщение StillZero »

Ну как в сях - имеешь _указатель_ на начало буфера, прочитал - указатель передвинул на длину прочитанного.
изначально так и собирался делать, но мне кажется что при уничтожении буфера я получу лики, а если я выберу вообще весь буфер, т.е. его длина станет равной нулю, то непонятно что вообще уничтожать :)

на данный момент использую связку memmove + realloc
memmove - это аналог memcpy, только корректно разруливает перекрывающиеся буфера, т.е. допустим надо уменьшить буфер на 1 байт:

Код: Выделить всё

 
 memmove(buf,buf+1,buf_len-1) ! сдвигаем буфер на 1 байт влево
 buf = realloc(buf,buf_len-1) ! изменяем размер буфера       
 buf_len -= 1
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3289
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 49 раз
Контактная информация:

Сообщение Дед Пахом »

я вообще-то имел в виду несколько другое:

Код: Выделить всё

указатель = адрес(начало_буфера)
пока указатель <= адрес(конец_буфера)
  len = сколько надо
  читаем указатель[1 : len]
  указатель += len
endпока
dispose(весь буфер целиком за раз)
С уважением, ДП
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Сообщение 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])
и всё - твои два действия сводятся к одному
Аватара пользователя
Admin
Администратор
Сообщения: 4010
Зарегистрирован: 05 Июль 2005, 15:59
Откуда: Хабаровск
Благодарил (а): 53 раза
Поблагодарили: 33 раза
Контактная информация:

Сообщение Admin »

А если без использования MAV нужно применить данную методу ...
Может быть откроешь код MAVString? :)
Рай совершает ошибки ничуть не реже чем ад. Просто у него хорошая пресса
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Сообщение Andrew™ »

Admin писал(а):А если без использования MAV нужно применить данную методу ...
Может быть откроешь код MAVString? :)
как говорится No Problem, ещё хочу заметить, много тестировал

realloc alloc, APIшные аналоги,

всё равно NEW DISPOSE NEW работает быстрее

http://mavcla.arsis.ru/Download/MAVString.rar

ЗЫ
ты получил моё сегодняшнее письмо, если да, То какие результаты
Аватара пользователя
Admin
Администратор
Сообщения: 4010
Зарегистрирован: 05 Июль 2005, 15:59
Откуда: Хабаровск
Благодарил (а): 53 раза
Поблагодарили: 33 раза
Контактная информация:

Сообщение Admin »

Результаты супер. Глюков нет!
В течении недели думаю если что то осталось выяснится ...
Рай совершает ошибки ничуть не реже чем ад. Просто у него хорошая пресса
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Сообщение Andrew™ »

Admin писал(а):Результаты супер. Глюков нет!
В течении недели думаю если что то осталось выяснится ...
ну тады закрывай ветку "Опять глюки!". не люблю это слово ;)

кстати, попробовал что то аналогичное в выходные состряпать и на FILE,DRIVER('ODBC') и на FILE,DRIVER('MSSQL') там вааще оказывается задача твоя невыполнима, прога ведёт себя непредказуемо, либо виснет, либо кричит "соединение занято другим открытым HTMT"
Аватара пользователя
Admin
Администратор
Сообщения: 4010
Зарегистрирован: 05 Июль 2005, 15:59
Откуда: Хабаровск
Благодарил (а): 53 раза
Поблагодарили: 33 раза
Контактная информация:

Сообщение Admin »

Я рад. Еще один плюс тебе на грудь :)))
Рай совершает ошибки ничуть не реже чем ад. Просто у него хорошая пресса
Леонид
Бывалый
Сообщения: 84
Зарегистрирован: 31 Август 2005, 17:07

Сообщение Леонид »

Andrew™ писал(а):[Изобретаешь велосипед, на сколько я знаю ты пользователь моей библиотеки и у тебя есть объект типа MAVString

Код: Выделить всё

tmp MAVString
  CODE
 tmp.Reset(tmp.S[2 : tmp.Pos])
и всё - твои два действия сводятся к одному
Андрей, а малюсенькое описание можешь кинуть по методам Reset, Insert...?
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Сообщение 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 при работе со строками, голова не болит о переполнении т к вроде ошибки и не будет, но инфо потеряется.
Ответить