Темиргалеев Е. Э. Использование SET вместо ARRAY n OF BOOLEAN в CpcBeautifierOptions

CpcBeautifierOptions — модуль компонента CpcBeautifier, в котором (на момент написания этой заметки) для хранения набора переключателей в настройках используется булевый массив.

  VAR
    param*: RECORD
      ...
      switch*: ARRAY 18 OF BOOLEAN
    END;

Нет никаких причин избегать1) использования типа SET2), эквивалентного3) ARRAY MAX(SET)+1 OF BOOLEAN4).

      switch*: SET

В данном случае такая замена прежде всего приводит к приличному сокращению исходного текста, содержащего param.switch, что делает его более обозримым и ясным. Также несколько сокращается объём кода и данных.

Задание настроек по-умолчанию в процедуре ResetBeautifier:

    param.switch[0] := FALSE;
    param.switch[1] := FALSE;
    param.switch[2] := FALSE;
    param.switch[3] := TRUE;
    param.switch[4] := FALSE;
    param.switch[5] := FALSE;
    param.switch[6] := FALSE;
    param.switch[7] := TRUE;
    param.switch[8] := TRUE;
    param.switch[9] := TRUE;
    param.switch[10] := TRUE;
    param.switch[11] := TRUE;
    param.switch[12] := TRUE;
    param.switch[13] := TRUE;
    param.switch[14] := TRUE;
    param.switch[15] := TRUE;
    param.switch[16] := FALSE;
    param.switch[17] := FALSE
    param.switch := {3, 7..15}

Чтение/запись param.switch в процедурах DoLoadOptions и SaveOptions:

        FOR i := 0 TO LEN(param.switch) - 1 DO
          rd.ReadBool(param.switch[i])
        END
и
        FOR i := 0 TO LEN(param.switch) - 1 DO
          wr.WriteBool(param.switch[i])
        END
    rd.ReadSet(param.switch)
и
    wr.WriteSet(param.switch)

В процедурах-охраны вида

  PROCEDURE XxxGuard* (VAR par: Dialog.Par);
  BEGIN
    par.disabled := ~param.switch[x]
  END XxxGuard;

будет замена

    par.disabled := ~(x IN param.switch)

Замечание (не относится к использованию SET): соответствующие охраны SpacesProTabGuard, ProcedureColorGuard и CommentColorGuard могут быть заменены одной процедурой5):

  PROCEDURE XxxGuard* (x: INTEGER; VAR par: Dialog.Par);
  BEGIN
    par.disabled := ~(x IN param.switch) (* ~param.switch[x] *)
  END XxxGuard;

07.06.2012

Исходник CpcBeautifierOptions

http://www.zinnamturm.eu/downloadsAC.htm#CpcBeautifier (Release 15-Mar-2012)

MODULE CpcBeautifierOptions;
 
  (* 2004-05-21 *)
 
  IMPORT
    Dialog, Files, Ports, StdLog, Stores;
 
  CONST
    optPath = "Cpc/Rsrc/";
    optName = "Beautifier.opt";
 
    (*
    -- switch:
    --  [0] = Clear Folds  [9] = Space Operators
    --  [1] = Clear Rulers  [10] = Space Parmeter Lists
    --  [2] = Clear Styles  [11] = Bold Breaking Keywords
    --
    --  [3] = Indent Check  [12] = Bold Exported Names
    --  [4] = Change Spaces To Tab  [13] = Color Procedure Names
    --  [5] = Remove Trailing Spaces  [14] = Color Comments
    --
    --  [6] = Remove Semicolons  [15] = Sort Import List
    --  [7] = Remove Double Spaces  [16] = Change Type
    --  [8] = Remove Single Spaces  [17] = Fold Procedure
    *)
 
  VAR
    param*: RECORD
      spacesProTab*: INTEGER;
      procedureColor*: INTEGER;
      commentColor*: INTEGER;
      switch*: ARRAY 18 OF BOOLEAN;
    END;
 
  PROCEDURE SpacesProTabGuard* (VAR par: Dialog.Par);
  BEGIN
    par.disabled := ~param.switch[4];
  END SpacesProTabGuard;
 
  PROCEDURE SpacesProTabNotifier* (op, from, to: INTEGER);
  BEGIN
    IF op = Dialog.changed THEN
      IF param.spacesProTab < 1 THEN param.spacesProTab := 1 END;
      IF param.spacesProTab > 9 THEN param.spacesProTab := 9 END;
      Dialog.Update(param);
    END;
  END SpacesProTabNotifier;
 
  PROCEDURE ProcedureColorGuard* (VAR par: Dialog.Par);
  BEGIN
    par.disabled := ~param.switch[13];
  END ProcedureColorGuard;
 
  PROCEDURE CommentColorGuard* (VAR par: Dialog.Par);
  BEGIN
    par.disabled := ~param.switch[14];
  END CommentColorGuard;
 
  PROCEDURE DoLoadOptions (): BOOLEAN;
    VAR
      i: INTEGER;
      rd: Stores.Reader;
      loc: Files.Locator;
      file: Files.File;
  BEGIN
    loc := Files.dir.This(optPath);
    IF loc # NIL THEN
      file := Files.dir.Old(loc, optName, FALSE);
      IF file # NIL THEN
        rd.ConnectTo(file);
        rd.ReadInt(param.spacesProTab);
        rd.ReadInt(param.procedureColor);
        rd.ReadInt(param.commentColor);
        FOR i := 0 TO LEN(param.switch) - 1 DO
          rd.ReadBool(param.switch[i]);
        END;
        file.Close;
        Dialog.Update(param);
        RETURN TRUE;
      END
    END;
    RETURN FALSE;
  END DoLoadOptions;
 
  PROCEDURE LoadOptions*;
  BEGIN
    IF ~DoLoadOptions() THEN
      StdLog.String("Error loading CpcBeautifier options"); StdLog.Ln;
    END;
  END LoadOptions;
 
  PROCEDURE SaveOptions*;
    VAR
      res, i: INTEGER;
      wr: Stores.Writer;
      loc: Files.Locator;
      file: Files.File;
  BEGIN
    loc := Files.dir.This(optPath);
    IF loc # NIL THEN
      file := Files.dir.New(loc, Files.dontAsk);
      IF file # NIL THEN
        wr.ConnectTo(file);
        wr.WriteInt(param.spacesProTab);
        wr.WriteInt(param.procedureColor);
        wr.WriteInt(param.commentColor);
        FOR i := 0 TO LEN(param.switch) - 1 DO
          wr.WriteBool(param.switch[i]);
        END;
        file.Register(optName, "", Files.dontAsk, res);
        IF res = 0 THEN RETURN END;
      END
    END;
    StdLog.String("Error saving CpcBeautifier options"); StdLog.Ln;
  END SaveOptions;
 
  PROCEDURE RGB (red, green, blue: INTEGER): INTEGER;
  BEGIN
    RETURN(blue * 256 + green) * 256 + red
  END RGB;
 
  PROCEDURE ResetBeautifier*;
  BEGIN
    param.spacesProTab := 3;
    param.procedureColor := RGB(172, 0, 0); (* red *)
    param.commentColor := RGB(0, 128, 64); (* green *)
    param.switch[0] := FALSE;
    param.switch[1] := FALSE;
    param.switch[2] := FALSE;
    param.switch[3] := TRUE;
    param.switch[4] := FALSE;
    param.switch[5] := FALSE;
    param.switch[6] := FALSE;
    param.switch[7] := TRUE;
    param.switch[8] := TRUE;
    param.switch[9] := TRUE;
    param.switch[10] := TRUE;
    param.switch[11] := TRUE;
    param.switch[12] := TRUE;
    param.switch[13] := TRUE;
    param.switch[14] := TRUE;
    param.switch[15] := TRUE;
    param.switch[16] := FALSE;
    param.switch[17] := FALSE;
    Dialog.Update(param);
  END ResetBeautifier;
 
BEGIN
  IF ~DoLoadOptions() THEN
    ResetBeautifier;
  END;
END CpcBeautifierOptions.
2) Элементы управления «Check Box» поддерживают SET в качестве переменной-интерактора. Подробнее см. документацию Блэкбокс (Controls, «Check Box»).
4) Для упоминаемой реализации КП MAX(SET) = 31.
5) Подробнее см. документацию Блэкбокс (Dialog.GuardProc).
© 2005-2018 OberonCore и коллектив авторов.