如何在私有类型上强制使用准确的索引
How to force accurate indices on a private type
我有一个内部使用二维数组的私有类型,同时在设置该数组的元素时进行额外处理。我的包裹看起来像这样:
with MyElements;
generic
Width, Height : Positive;
package MyPackage is
subtype MyXCoordinate is Positive range 1..Width;
subtype MyYCoordinate is Positive range 1..height;
type MyCoordinate is
record
x : MyXCoordinate;
y : MyYCoordinate;
end record;
type MyType is private;
function Create return MyType;
function Get (this : in MyType;
coord : in MyCoordinate) return MyElements.MyElementType;
procedure Set (this : out MyType;
coord : in MyCoordinate;
element : in MyElements.MyElementType);
private
type MyTypeData is array (MyXCoordinate,MyYCoordinate)
of MyElements.MyElementType;
type MyType is
record
data : MyTypeData;
otherstuff : ThatIsActuallyInThePackageButNotRelevant;
end record;
end MyPackage
然而,这会强制与 MyPackage 接口的包要么是通用的,要么使用正确的参数动态实例化一个新的 MyPackage。在执行过程中,这些参数很早就可用(它们是从命令行传入的文件中读取的),但似乎我仍然缺少可以为我执行此操作的语言元素。
我考虑过只对坐标使用未绑定的正值,删除泛型并允许在边界失败时生成 运行 时间越界错误,但我不禁觉得 Ada 必须有一些在编译时干净地执行此操作的方法。
我知道我可以使用 SPARK,但它对这个项目来说太过分了(这个项目是一个游戏,用 Ada 编写以展示其品质)并且有点违背了它的目的(展示 Ada 的编译时错误检查!)。
我的通用实例化解决方案是处理这个问题的正确方法吗,还是有更好的方法?
到目前为止,我的尝试没有奏效,但感觉它们可能很接近:
type MyType is
record
Width,Height : Positive;
subtype XCoordinate is Positive 1..Width;
subtype YCoordinate is Positive 1..Height;
data : array (XCoordinate,YCoordinate) of MyElements.MyElementType;
end record;
并用 'generator' 包包装通用包,该包将 width/height 作为函数和过程的参数,然后调用包。 (很多代码,不起作用,不会在这里浪费 space)。
看来您需要阅读判别式、无约束数组和不定类型。
这是一个通用包,它解决了您实际遇到的问题:
generic
type Element_Type is private;
package Dynamic_Matrix is
type Instance (Width, Height : Positive) is tagged private;
procedure Set (Item : in out Instance;
X, Y : in Positive;
Value : in Element_Type)
with Pre => X <= Item.Width and Y <= Item.Height;
function Element (Item : in Instance;
X, Y : in Positive) return Element_Type
with Pre => X <= Item.Width and Y <= Item.Height;
private
type Element_Matrix is array (Integer range <>,
Integer range <>) of Element_Type;
type Instance (Width, Height : Positive) is tagged
record
Elements : Element_Matrix (1 .. Width, 1 .. Height);
end record;
end Dynamic_Matrix;
下面是一个使用包将布尔矩阵加载到变量中的示例:
with Ada.Text_IO;
with Dynamic_Matrix;
procedure Dynamic_Matrix_Demo is
package Positive_IO is new Ada.Text_IO.Integer_IO (Positive);
package Boolean_IO is new Ada.Text_IO.Enumeration_IO (Boolean);
package Boolean_Matrix is new Dynamic_Matrix (Element_Type => Boolean);
Width, Height : Positive;
use Ada.Text_IO, Positive_IO, Boolean_IO;
begin
Get (Width);
Get (Height);
Skip_Line;
declare
Matrix : Boolean_Matrix.Instance (Width => Width,
Height => Height);
Value : Boolean;
begin
for Y in 1 .. Height loop
for X in 1 .. Width loop
Get (Value);
Matrix.Set (X, Y, Value);
end loop;
Skip_Line;
end loop;
end;
end Dynamic_Matrix_Demo;
我有一个内部使用二维数组的私有类型,同时在设置该数组的元素时进行额外处理。我的包裹看起来像这样:
with MyElements;
generic
Width, Height : Positive;
package MyPackage is
subtype MyXCoordinate is Positive range 1..Width;
subtype MyYCoordinate is Positive range 1..height;
type MyCoordinate is
record
x : MyXCoordinate;
y : MyYCoordinate;
end record;
type MyType is private;
function Create return MyType;
function Get (this : in MyType;
coord : in MyCoordinate) return MyElements.MyElementType;
procedure Set (this : out MyType;
coord : in MyCoordinate;
element : in MyElements.MyElementType);
private
type MyTypeData is array (MyXCoordinate,MyYCoordinate)
of MyElements.MyElementType;
type MyType is
record
data : MyTypeData;
otherstuff : ThatIsActuallyInThePackageButNotRelevant;
end record;
end MyPackage
然而,这会强制与 MyPackage 接口的包要么是通用的,要么使用正确的参数动态实例化一个新的 MyPackage。在执行过程中,这些参数很早就可用(它们是从命令行传入的文件中读取的),但似乎我仍然缺少可以为我执行此操作的语言元素。
我考虑过只对坐标使用未绑定的正值,删除泛型并允许在边界失败时生成 运行 时间越界错误,但我不禁觉得 Ada 必须有一些在编译时干净地执行此操作的方法。
我知道我可以使用 SPARK,但它对这个项目来说太过分了(这个项目是一个游戏,用 Ada 编写以展示其品质)并且有点违背了它的目的(展示 Ada 的编译时错误检查!)。
我的通用实例化解决方案是处理这个问题的正确方法吗,还是有更好的方法?
到目前为止,我的尝试没有奏效,但感觉它们可能很接近:
type MyType is
record
Width,Height : Positive;
subtype XCoordinate is Positive 1..Width;
subtype YCoordinate is Positive 1..Height;
data : array (XCoordinate,YCoordinate) of MyElements.MyElementType;
end record;
并用 'generator' 包包装通用包,该包将 width/height 作为函数和过程的参数,然后调用包。 (很多代码,不起作用,不会在这里浪费 space)。
看来您需要阅读判别式、无约束数组和不定类型。
这是一个通用包,它解决了您实际遇到的问题:
generic
type Element_Type is private;
package Dynamic_Matrix is
type Instance (Width, Height : Positive) is tagged private;
procedure Set (Item : in out Instance;
X, Y : in Positive;
Value : in Element_Type)
with Pre => X <= Item.Width and Y <= Item.Height;
function Element (Item : in Instance;
X, Y : in Positive) return Element_Type
with Pre => X <= Item.Width and Y <= Item.Height;
private
type Element_Matrix is array (Integer range <>,
Integer range <>) of Element_Type;
type Instance (Width, Height : Positive) is tagged
record
Elements : Element_Matrix (1 .. Width, 1 .. Height);
end record;
end Dynamic_Matrix;
下面是一个使用包将布尔矩阵加载到变量中的示例:
with Ada.Text_IO;
with Dynamic_Matrix;
procedure Dynamic_Matrix_Demo is
package Positive_IO is new Ada.Text_IO.Integer_IO (Positive);
package Boolean_IO is new Ada.Text_IO.Enumeration_IO (Boolean);
package Boolean_Matrix is new Dynamic_Matrix (Element_Type => Boolean);
Width, Height : Positive;
use Ada.Text_IO, Positive_IO, Boolean_IO;
begin
Get (Width);
Get (Height);
Skip_Line;
declare
Matrix : Boolean_Matrix.Instance (Width => Width,
Height => Height);
Value : Boolean;
begin
for Y in 1 .. Height loop
for X in 1 .. Width loop
Get (Value);
Matrix.Set (X, Y, Value);
end loop;
Skip_Line;
end loop;
end;
end Dynamic_Matrix_Demo;