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/