OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Суббота, 23 Март, 2019 13:26

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 4 ] 
Автор Сообщение
 Заголовок сообщения: Работа с массивами
СообщениеДобавлено: Понедельник, 31 Август, 2015 11:27 

Зарегистрирован: Суббота, 05 Март, 2011 05:10
Сообщения: 10
Можно ли в КП создавать массив произвольного размера, а потом расширять его?
То бишь:

Код:
newArray: POINTER TO ARRAY OF REAL;
...
NEW(newArray, 10);
...
Занесли данные в массив
...
Возникла необходимость добавить новые данные в массив


Если снова писать NEW(newArray, 100), то старые данные сотрутся. Можно ли расширить массив без удаления старых данных?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Работа с массивами
СообщениеДобавлено: Понедельник, 31 Август, 2015 11:41 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2559
Откуда: Россия, Ярославль
elvennight писал(а):
Можно ли расширить массив без удаления старых данных?

Нет. Нельзя.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Работа с массивами
СообщениеДобавлено: Понедельник, 31 Август, 2015 11:43 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9099
Откуда: Россия, Орёл
Когда-то давно эти функции входили в мою библиотеку Mt, которую мы потом сняли с публикации.

Дать однозначно рекомендации по тому "хороший стиль это или нет" - использовать релокацию массивов, не знаю...

В своё время я перестал использовать и распространять этот модуль в силу соображений, что он завязан на внутренние соглашения ядра ББ, которое может меняться разработчикам (так, что релокация станет, допустим, невозможной вообще).

Сейчас, однако, с переходом ББ в развитие сообществом(ами), этот фактор уже некритичен.

Так что, если хотите, пользуйтесь.

Код:
MODULE OmcDynAr;
   IMPORT Kernel, S := SYSTEM;
   
   (* TODO: должен быть резерв по-умолчанию. И сейчас SetReserve вызывает релокацию, лишнюю.
      Сделать процедуры копирования участков дин. массивов. *)

   CONST
      reserveOff = FALSE;

   TYPE
      Block = POINTER TO RECORD [untagged]
         tag: Kernel.Type;
         last: INTEGER;      (* arrays: last element *)
         actual: INTEGER;   (* arrays: used during mark phase *)
         first: INTEGER;      (* arrays: first element *)
         len: ARRAY 16 OF INTEGER
      END;
   
   PROCEDURE ^ SetReserve* (VAR array: S.PTR; count: INTEGER);

   PROCEDURE SetLength* (VAR array: S.PTR; len: INTEGER);
      VAR old: INTEGER; (* Old array address *)
            tag: INTEGER; (* Old array tag *)
            type: Kernel.Type; (* Elem type *)
            oldBlock: Block; (* Old array block *)
            dim: INTEGER; (* Dimension of array *)
            oldSize, oldLen: INTEGER; (* Size of array block (in elem count), array actual len *)
            reserve: INTEGER; (* If array has been resized with Reserve proc, it's reserved count *)
            (* For new array *)
            new: INTEGER;
            newSize: INTEGER;
            newBlock: Block;
            i, j: INTEGER;
   BEGIN
      (* Parsing array params *)
      ASSERT(len >= 0, 20);
      S.GET(S.ADR(array), old);
      ASSERT(old # 0, 21);

      S.GET(old-SIZE(INTEGER), tag);
      ASSERT(1 IN BITS(tag), 22); (* Check array mark *)
      type := S.VAL(Kernel.Type, tag-2);
      oldBlock := S.VAL(Block, old-SIZE(INTEGER));
      dim := (oldBlock.first - old - 3*SIZE(INTEGER)) DIV 4;
      ASSERT(dim = 1, 23);

      oldSize := (oldBlock.last - oldBlock.first) DIV type.size + 1;
      S.GET(old + 3*SIZE(INTEGER), oldLen);
      
      reserve := oldSize - oldLen;
      ASSERT(0 <= reserve, 24);
      
      IF len <= oldSize THEN
         S.PUT(old + 3*SIZE(INTEGER), len);
         IF len < oldLen THEN
            (* FillMemory(oldBlock.first + oldLen * type.size, (len - oldLen) * type.size, 0) *)
               j := oldBlock.first + oldLen * type.size;
               FOR i := 0 TO (len - oldLen) * type.size -1 DO
                  S.PUT(j + i, S.VAL(BYTE, 0))
               END
         END
      ELSE
         newSize := len + reserve;
         new := Kernel.NewArr(S.VAL(INTEGER, type), newSize, 1);
         newBlock := S.VAL(Block, new-SIZE(INTEGER));
         S.PUT(new + 3*SIZE(INTEGER), len);
         S.MOVE(oldBlock.first, newBlock.first, MIN(oldLen, len) * type.size);
         S.PUT(S.ADR(array), new)
      END
   END SetLength;

   PROCEDURE BaseType (type: Kernel.Type): INTEGER;
   BEGIN
      IF (type.mod.name = "Kernel") & (type.fields.num = 1) THEN
         RETURN S.VAL(INTEGER, type.fields.obj[0].struct)
      ELSE
         RETURN S.VAL(INTEGER, type)
      END
   END BaseType;

   PROCEDURE SetReserve* (VAR array: S.PTR; count: INTEGER);
      VAR old: INTEGER; (* Old array address *)
            tag: INTEGER; (* Old array tag *)
            type: Kernel.Type; (* Elem type *)
            oldBlock: Block; (* Old array block *)
            dim: INTEGER; (* Dimension of array *)
            oldSize, oldLen: INTEGER; (* Size of array block (in elem count), array actual len *)
            reserve: INTEGER; (* If array has been resized with Reserve proc, it's reserved count *)
            (* For new array *)
            new: INTEGER;
            newSize: INTEGER;
            newBlock: Block;
            i, j: INTEGER;
   BEGIN
      IF reserveOff & (count # 0) THEN RETURN END;
      (* Parsing array params *)
      ASSERT(count >= 0, 20);
      S.GET(S.ADR(array), old);
      ASSERT(old # 0, 21);

      S.GET(old-SIZE(INTEGER), tag);
      ASSERT(1 IN BITS(tag), 22); (* Check array mark *)
      type := S.VAL(Kernel.Type, tag-2);
      
      oldBlock := S.VAL(Block, old-SIZE(INTEGER));
      dim := (oldBlock.first - old - 3*SIZE(INTEGER)) DIV 4;
      ASSERT(dim = 1, 23); (* Array is dynamic one-dimensional *)

      oldSize := (oldBlock.last - oldBlock.first) DIV type.size + 1;
      S.GET(old + 3*SIZE(INTEGER), oldLen);

      IF oldLen < oldSize THEN (* If array has been resised... *)
         S.GET(oldBlock.last, reserve)  (* lookup mark by Reserve proc *)
      ELSE
         reserve := 0
      END;

      IF (reserve = count + 1) OR ((reserve = 0) & (count = 0)) THEN RETURN END;

      (* Calc new array size (in elem count) *)
      IF count = 0 THEN
         newSize := oldLen
      ELSE
         newSize := oldLen + count + 1
      END;

      (* Cteating new array *)
      new := Kernel.NewArr(S.VAL(INTEGER, type), newSize, 1);
      newBlock := S.VAL(Block, new-SIZE(INTEGER));
      IF (count > 0) & (BaseType(type) # 13) THEN
         S.PUT(newBlock.last, count + 1) (* set reserve mark for non-pointer arrays *)
      END;
      S.PUT(new + 3*SIZE(INTEGER), oldLen);
      (* Copying old array *)
      S.MOVE(oldBlock.first, newBlock.first, oldLen * type.size);
      S.PUT(S.ADR(array), new)
   END SetReserve;
   
END OmcDynAr.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Работа с массивами
СообщениеДобавлено: Понедельник, 31 Август, 2015 16:31 
Аватара пользователя

Зарегистрирован: Четверг, 08 Октябрь, 2009 15:00
Сообщения: 2257
Очень простая но, к сожалению, ресурсоемкая реализация есть у меня в DiaArray

http://redmine.molpit.com/projects/blac ... /Array.odc


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 4 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2019, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB