指定具有无效值的范围的惯用方法是什么?

Chr*_*bbs 1 ada

我经常发现我需要指定一个变量从具有某种物理意义的范围(例如,SoC 上的特定核心)获取值。但我还需要能够将其设置为“无”,这意味着“目前它不持有真正的核心标识符”。我通常使用下面给出的两种模式之一来实现此目的,但每种模式都有缺点:

  1. 第一个需要定义额外的(而且确实不必要的)类型。

  2. 第二个要求手动保持两个字段(值和定义该值是否有效的字段)对齐。编译器无法检查这种对齐方式。

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

  --  We want to specify a Unit Identifier in the range 1 .. 10.
  --  However, sometimes we need to say that the Unit Identifier
  --  being stored is invalid.
  --
  --  The first way of doing this is to define an extended range
  --  and an Invalid Identifier.

  type Extended_Core_Identifier is new Natural range 0 .. 10;
  subtype Core_Identifier is Extended_Core_Identifier range 1 .. 10;

  Invalid_Core : constant Extended_Core_Identifier := 0;

  --  The second way is to define the range to be what we actually
  --  want and then define a Boolean to say whether the value is valid.

  type Second_Try_Identifier is new Natural range 1 .. 10;
  Identifier_Is_Valid : Boolean := False;
  Identifier1 : Extended_Core_Identifier := Invalid_Core;
  Identifier2 : Second_Try_Identifier    := 6;

begin
  if Identifier1 = Invalid_Core then
    Put_Line ("Identifier1 does not hold a real core");
  end if;

  if not Identifier_Is_Valid then
    Put_Line ("Identifier2 is not a real core");
  end if;

end Main;
Run Code Online (Sandbox Code Playgroud)

Jer*_*ere 5

我喜欢在这种情况下使用变体记录。它允许您指定仅当有效判别式设置为 True 时 ID 才存在。它还允许 Ada 的强类型检查来强制执行该不变式(即,如果您尝试访问无效核心的 ID,代码将引发异常)。

with Ada.Text_IO; use Ada.Text_IO;

procedure Hello is

    type Core_Identifier is new Positive range 1 .. 10;

    type Core (Valid : Boolean := False) is record
        case Valid is
            when True  => ID : Core_Identifier := 1;
            when False => null;
        end case;
    end record;
    
    Invalid_Core : constant Core := (Valid => False);
    
    -- Constructing function
    function Make_Core(ID : Core_Identifier) return Core
        is (Valid => True, ID => ID);
    
    -- Various initialization methods
    Core_1 : Core := Invalid_Core;
    Core_2 : Core := (Valid => True, ID => 6);
    Core_3 : Core := Make_Core(9);
    Core_4 : Core := (Valid => False);

begin
    Put_Line("Hello, world!");
  
    if not Core_1.Valid then
        Put_Line("Core 1 invalid");
    else
        Put_Line("Core 1 ID:" & Core_1.ID'Image);
    end if;
    
    if not Core_2.Valid then
        Put_Line("Core 2 invalid");
    else
        Put_Line("Core 2 ID:" & Core_2.ID'Image);
    end if;
    
    if not Core_3.Valid then
        Put_Line("Core 3 invalid");
    else
        Put_Line("Core 3 ID:" & Core_3.ID'Image);
    end if;
    
    if not Core_4.Valid then
        Put_Line("Core 4 invalid");
    else
        Put_Line("Core 4 ID:" & Core_4.ID'Image);
    end if;
    
end Hello;
Run Code Online (Sandbox Code Playgroud)