OberonCore https://forum.oberoncore.ru/ |
|
Пример на цикл: поиск места между указателями в RECORD https://forum.oberoncore.ru/viewtopic.php?f=82&t=6575 |
Страница 1 из 2 |
Автор: | Илья Ермаков [ Вторник, 03 Март, 2020 13:47 ] |
Заголовок сообщения: | Пример на цикл: поиск места между указателями в RECORD |
Коллеги, предлагаю размяться на таком примере: - как известно, тип в ББ описывается следующим дескриптором Kernel.Type: Код: TYPE Type = POINTER TO RECORD [untagged] size-: INTEGER; mod-: Kernel.Module; id-: INTEGER; base-: ARRAY 16 OF Kernel.Type; fields-: Kernel.Directory; ptroffs-: ARRAY 1000000 OF INTEGER END; Здесь ptroffs - это смещения, по которым в записи есть указательные поля (для сборщика мусора). Список заканчивается значением -1. Задача: составить процедуру PROCEDURE LookupMarkOffs (t: Kernel.Type): INTEGER, которая находит смещение в записи, по которому мы можем безопасно положить значение INTEGER, не попав на указательные поля (не сломав зубы сборщику). Если класть некуда, то вернуть -1. У меня решение уже есть. |
Автор: | adimetrius [ Вторник, 03 Март, 2020 14:53 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
.ptroffs полагаем строго монотонно возрастающим? |
Автор: | Илья Ермаков [ Вторник, 03 Март, 2020 16:08 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
adimetrius писал(а): .ptroffs полагаем строго монотонно возрастающим? Да, это обеспечивается реализацией компилятора. |
Автор: | Rifat [ Вторник, 03 Март, 2020 16:48 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
При выделении памяти, менеджер памяти, обычно выделяет память не байт в байт, а определенным блоками. Например, в менедержере памяти Oberon-07M память выделяется от 32 байт до мегабайта кратно степени двойки. А с мегабайта кратно мегабайту. В BlackBox скорее всего примерно то же самое, соответственно в конце блока должно быть еще много места, чтобы не просто INTEGER сохранить, а еще много чего можно сохранить. |
Автор: | Илья Ермаков [ Вторник, 03 Март, 2020 17:41 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Rifat писал(а): При выделении памяти, менеджер памяти, обычно выделяет память не байт в байт, а определенным блоками. Например, в менедержере памяти Oberon-07M память выделяется от 32 байт до мегабайта кратно степени двойки. А с мегабайта кратно мегабайту. В BlackBox скорее всего примерно то же самое, соответственно в конце блока должно быть еще много места, чтобы не просто INTEGER сохранить, а еще много чего можно сохранить. Не обязательно, если поля записи кратно уложатся в эту гранулярность. А в моём случае вообще речь идёт о метке в элементе динамического массива. А постановка задачи на алгоритмику ![]() |
Автор: | adimetrius [ Вторник, 03 Март, 2020 23:13 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Чую подвох, но рискну размяться: Код: MODULE M;
IMPORT Kernel; PROCEDURE P (IN a: ARRAY OF INTEGER; size: INTEGER): INTEGER; VAR i, res: INTEGER; BEGIN i := 0; WHILE (a[i] # -1) & (a[i] + 8 <= a[i + 1]) DO INC(i) END; IF a[i] = -1 THEN res := -1 ELSE res := a[i] + 4; IF res + 4 > size THEN res := -1 END END; RETURN res END P; PROCEDURE LookupMarkOffs (t: Kernel.Type): INTEGER; BEGIN RETURN P(t.ptroffs, t.size) END LookupMarkOffs; END M. |
Автор: | Илья Ермаков [ Вторник, 03 Март, 2020 23:32 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Не, читается неубедительно - и, по ходу, пропускает случай, когда свободное место есть ещё до первого указателя. |
Автор: | adva [ Среда, 04 Март, 2020 09:07 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Не очень понимаю всех полей, но если правильно понял, то наверное так (исправил предыдущий пример. Верен, если размер указателя такой же, как интегера) Код: MODULE M;
IMPORT Kernel; PROCEDURE P (IN a: ARRAY OF INTEGER; size: INTEGER): INTEGER; VAR i, res, sizeInt: INTEGER; BEGIN sizeInt := 8; IF a[0] > sizeInt THEN res := 0; ELSE i := 0; WHILE (a[i + 1] # -1) & (a[i] + sizeInt > a[i + 1]) DO INC(i) END; IF a[i + 1] = -1 THEN res := -1 ELSE res := a[i] + sizeInt; END; END; RETURN res END P; PROCEDURE LookupMarkOffs (t: Kernel.Type): INTEGER; BEGIN RETURN P(t.ptroffs, t.size) END LookupMarkOffs; END M. |
Автор: | adva [ Среда, 04 Март, 2020 09:12 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Ну и еще предусмотреть случаи, когда количество в массиве меньше 2х |
Автор: | Trurl [ Среда, 04 Март, 2020 14:40 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Код: i:=0;
WHILE i=p[i] DO INC(i) END; IF i >= size THEN i := -1 END; |
Автор: | Илья Ермаков [ Среда, 04 Март, 2020 14:55 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Trurl писал(а): Код: i:=0; WHILE i=p[i] DO INC(i) END; IF i >= size THEN i := -1 END; Не, что-то не то. Возможно, Вы считаете, что в ptroffs лежит не смещение в байтах, а что-то другое. Пример. Первый указатель лежит по смещению 0. У Вас цикл остановится уже на i = 1. Результатом станет смещение в 1 байт? |
Автор: | Илья Ермаков [ Среда, 04 Март, 2020 14:58 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
adva писал(а): Не очень понимаю всех полей, но если правильно понял, то наверное так (исправил предыдущий пример. Верен, если размер указателя такой же, как интегера) У Вас в условии цикла не учитывается ещё то, что от предыдущего ptroffs до начала следующего должно "пролезать" 2 IntSize. Ну, лучше вообще использовать 2 разных размера: SIZE(ANYPTR) и SIZE(INTEGER). Ну и можно вообще без начальных IF-ов и разбора ситуаций, сразу циклом. В конце, конечно, IF. |
Автор: | Peter Almazov [ Среда, 04 Март, 2020 16:04 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Если я правильно понял условие, то середина такая Код: prev=начало области
i=0 WHILE a[i]!=-1 and (a[i] - prev < нужный_кусок) DO prev=a[i] i=i+1 END |
Автор: | Trurl [ Среда, 04 Март, 2020 16:24 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Илья Ермаков писал(а): Возможно, Вы считаете, что в ptroffs лежит не смещение в байтах, а что-то другое. Ну да. Я считал все в машинных словах. тогда так Код: i:=0;
WHILE 4*i=p[i] DO INC(i) END; i := 4*i; IF i >= size THEN i := -1 END; |
Автор: | adva [ Среда, 04 Март, 2020 17:03 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Илья Ермаков писал(а): Ну и можно вообще без начальных IF-ов и разбора ситуаций, сразу циклом. В конце, конечно, IF. А без IF в конце? Так не сработает? Ну и не против увидеть, "разбор правильного решения". Код: res := -1;
i := 0; WHILE (a[i] # -1) & (res = -1) DO IF i > 0 & (a[i] - SIZE(anyptr) - SIZE(INTEGER) > a[i - 1]) OR (a[i] - SIZE(anyptr) - SIZE(INTEGER) >= 0) res := a[i] - SIZE(INTEGER) END; INC(i) END; |
Автор: | albobin [ Среда, 04 Март, 2020 17:19 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
приблизительно Код: res:=0;
i:=0; eof:=FALSE; WHILE ~eof & res+8>a[i] DO eof:= (a[i]=-1) or (i=imax); res:=a[i]+8; INC(i); END IF eof THEN res:=-1 END |
Автор: | Sergej Durmanov [ Среда, 04 Март, 2020 19:35 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Код: i := 0; start := 0; end := ptroffset[ 0 ];
WHILE ( end # -1 ) & ( end - start < 4 ) DO INC( i ); start := end; end := ptroffset[ i ]; END; IF size - start < 4 THEN start := -1; END; |
Автор: | Илья Ермаков [ Среда, 04 Март, 2020 21:46 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Ну Пётр Алмазов первым представил самое лучшее по понятности решение. Хотя там есть нюансы (внутри цикла prev выставляется как начало предыдущего указателя, а не место по его окончанию, надо + SIZE(ANYPTR)). Ну и моё. Сначала я немного потупил, взяв отдельно ползунок возможных смещений для числа (ползущий с каким-то шагом) и итератор по ptroffs. После чего инвариант, объединяющий движение по двум последовательностям, получался мама не горюй. Потом понял, что нужно сформулировать задачу только относительно ptroffs. Получилось: "Найти такой ptroffs[i], перед которым есть место для целого числа, или достичь конца". Разумеется, в конце уже проверка на то, нет ли места в конце. Получился типовой линейный поиск с удачным выбором переменных цикла (чтобы они могли быть хорошо определены и до цикла, и в нём, и после, а не как в случае с i и i-1 или с переменной, задающей НАЧАЛО предыдущего указателя, а если его не было, строить от отрицательного смещения?) и некоторыми поддерживающими рассуждениями после. Код с некоторыми сопутствующими рассуждениями (писал не для форума, так и есть в коде): Код: PROCEDURE LookupMarkOffs (t: Kernel.Type): INTEGER; VAR spaceBeg, pi: INTEGER; BEGIN spaceBeg := 0; (* Где заканчивается предыдущий указатель *) pi := 0; (* Найти такой указатель среди ptroffs, перед которым есть свободное место для целого числа *) WHILE (t.ptroffs[pi] # -1) & ~(spaceBeg + SIZE(INTEGER) <= t.ptroffs[pi]) DO spaceBeg := t.ptroffs[pi] + SIZE(ANYPTR); INC(pi) END; (* Q: Если pi найден (ptroffs[pi] # -1), то spaceBeg - начало свободного пространства перед ним (=> spaceBeg + SIZE(INTEGER) < t.size) Если pi не найден, то spaceBeg - пространство после последнего указателя. Надо проверить, что spaceBeg + SIZE(INTEGER) < t.size *) IF spaceBeg + SIZE(INTEGER) <= t.size THEN RETURN spaceBeg ELSE RETURN -1 END END LookupMarkOffs; |
Автор: | Peter Almazov [ Среда, 04 Март, 2020 22:05 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Илья Ермаков писал(а): Хотя там есть нюансы (внутри цикла prev выставляется как начало предыдущего указателя, а не место по его окончанию, надо + SIZE(ANYPTR)). Нет, не надо. Там фигурирует "нужный_кусок" - его величина как раз и должна включать добавку. |
Автор: | Peter Almazov [ Среда, 04 Март, 2020 22:17 ] |
Заголовок сообщения: | Re: Пример на цикл: поиск места между указателями в RECORD |
Вообще, Илья, давно пора завязывать с этой ахинеей (базовые паттерны циклов, обожествление линейного поиска) и научиться уже писать циклы. Инвариант там простой – в просмотренной части нет подходящего свободного куска. |
Страница 1 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |