OberonCore https://forum.oberoncore.ru/ |
|
Работа с массивами https://forum.oberoncore.ru/viewtopic.php?f=29&t=5479 |
Страница 1 из 1 |
Автор: | elvennight [ Понедельник, 31 Август, 2015 11:27 ] |
Заголовок сообщения: | Работа с массивами |
Можно ли в КП создавать массив произвольного размера, а потом расширять его? То бишь: Код: newArray: POINTER TO ARRAY OF REAL; ... NEW(newArray, 10); ... Занесли данные в массив ... Возникла необходимость добавить новые данные в массив Если снова писать NEW(newArray, 100), то старые данные сотрутся. Можно ли расширить массив без удаления старых данных? |
Автор: | Пётр Кушнир [ Понедельник, 31 Август, 2015 11:41 ] |
Заголовок сообщения: | Re: Работа с массивами |
elvennight писал(а): Можно ли расширить массив без удаления старых данных? Нет. Нельзя. |
Автор: | Илья Ермаков [ Понедельник, 31 Август, 2015 11:43 ] |
Заголовок сообщения: | Re: Работа с массивами |
Когда-то давно эти функции входили в мою библиотеку 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. |
Автор: | Иван Денисов [ Понедельник, 31 Август, 2015 16:31 ] |
Заголовок сообщения: | Re: Работа с массивами |
Очень простая но, к сожалению, ресурсоемкая реализация есть у меня в DiaArray http://redmine.molpit.com/projects/blac ... /Array.odc |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |