Arrays 如何实现未经检查的访问

Arrays 如何实现未经检查的访问,arrays,ada,gnat,Arrays,Ada,Gnat,我正在尝试设计一个自动扩展的2D阵列 矩形广告 generic type Value_Type is private; package Rectangular is function Get ( Row, Col : Integer) return Value_Type; procedure Set ( Row, Col : Integer; Value : Value_Type); private type Matrix is array

我正在尝试设计一个自动扩展的2D阵列

矩形广告

generic
    type Value_Type is private;

package Rectangular is
    
    function Get ( Row, Col : Integer) return Value_Type;
    procedure Set ( Row, Col : Integer; Value : Value_Type);
    
private
    type Matrix is array (Integer range <>, Integer range <>) of aliased Value_Type;
    
    Item : access Matrix;
    
end Rectangular;
generic
    type Element is private;
    Default : Element;

package Rectangular is
-- Provides an X..Y matrix of Element, which can be used just like a 2D Array.
-- The bounds of the array adjust themselves to accomodate requested indexes.
-- Rule-of-thumb: ~5 millseconds to re-allocate an array of 1'000'000 (1'000 x 1'000) entries. YMMV.
-- Usage:
--    package Rect is new Rectangular (Element => Float, Default => 0.0);
--    use Rect;
--    Map : Rect.Matrix;
--    ...
--    Map(-25, 97) := 42.0;
-- The bounds are now -25..0, 0..97, 2'548 elements, all 0.0 except -25,97 = 42.0
    
    type Matrix is tagged limited private
      with 
         Constant_Indexing => Get_Element,
         Variable_Indexing => Get_Reference;

    type Element_Access is access all Element;

    function Get_Element (M : in out Matrix; E : in Element_Access) return Element;

    function Get_Element (M : in out Matrix; Row, Col : in Integer) return Element;

    type Reference (R : access Element) is limited null record
      with Implicit_Dereference => R;

    function Get_Reference (M : in out Matrix; E : in Element_Access) return Reference;

    function Get_Reference (M : in out Matrix; Row, Col : in Integer) return Reference;

private
    type Backing is array (Integer range <>, Integer range <>) of Element;
    type Backing_Access is access Backing;
    type Matrix is tagged limited record
        Items : Backing_Access;
    end record;
end Rectangular;
这是编译的,但带有

   6:17 warning: "Program_Error" will be raised at run time
   6:17 warning: accessibility check failure
   6:17 warning: in instantiation at rectangular.adb:29
当然,当我尝试运行它时,我得到了程序错误:矩形。adb:59可访问性检查失败

我不明白为什么,因为在块的范围之外不能清楚地访问“Rect”

我应该使用未经检查的访问来避免这种行为吗?如果是的话,它会是什么样子? 如果不是,正确的成语是什么? 我应该如何释放矩形中的“项”? 几天来,我一直在努力让它正常工作,但都没有成功,如果您能提供代码示例帮助,我将不胜感激。

在类型矩阵之后添加

使用您自己的约定命名访问类型

然后,用矩阵p全局替换访问矩阵

然后,在Adjust_界限中,您似乎需要替换

      Rowmax := Integer'Min (Item'Last (1), Row);

对于Colmax也是如此。

在类型矩阵之后添加

使用您自己的约定命名访问类型

然后,用矩阵p全局替换访问矩阵

然后,在Adjust_界限中,您似乎需要替换

      Rowmax := Integer'Min (Item'Last (1), Row);


<> P>> CalMax。

< P>您可以考虑使用以下包规范中所示的模式来制作可扩展矩阵:

with Ada.Containers.Vectors;
generic
   type Index_Type is range <>;
   with package inner_vector is new Ada.Containers.Vectors(<>);
package Vector_Of_Vectors is
   package V_Matrix is new Ada.Containers.Vectors(Index_Type   => Index_Type,
                                                  Element_Type => Inner_Vector.Vector,
                                                  "="          => Inner_Vector."=");
   use Inner_Vector;
end Vector_Of_Vectors;
现在,您可以修改V_矩阵类型的每个向量元素的长度,以及向V_矩阵添加更多向量元素

下面是实例化向量包中的向量包的一个小示例:

with Ada.Containers.Vectors;
with Vector_Of_Vectors;
with Ada.Text_IO; use Ada.Text_IO;
use Ada.Containers;

procedure Main is
   package Int_Vector is new Ada.Containers.Vectors(Index_Type => Natural,
                                                    Element_Type => Integer);
   use Int_Vector;
   
   package Int_Matrix is new Vector_Of_Vectors(Index_Type   => Natural,
                                               inner_vector => Int_Vector);
   use Int_Matrix;
   
   Temp_Vect : Int_Vector.Vector;
   Temp_Mat  : V_Matrix.Vector;
begin

   Temp_Vect := Int_Vector.Empty_Vector;
   for I in 1..5 loop
      Temp_Vect.append(I);
   end loop;
   
   Temp_Mat.Append(Temp_Vect);
    
   temp_Vect := Int_Vector.Empty_Vector;
    
   for I in 15..25 loop
      Temp_Vect.append(I);
   end loop;
   Temp_Mat.Append(Temp_Vect);
     
   for V of Temp_Mat loop
      for I of V loop
         Put(I'Image);
      end loop;
      New_Line;
   end loop;
end Main;

您可以考虑使用以下包规范中所示的模式来创建可扩展矩阵:

with Ada.Containers.Vectors;
generic
   type Index_Type is range <>;
   with package inner_vector is new Ada.Containers.Vectors(<>);
package Vector_Of_Vectors is
   package V_Matrix is new Ada.Containers.Vectors(Index_Type   => Index_Type,
                                                  Element_Type => Inner_Vector.Vector,
                                                  "="          => Inner_Vector."=");
   use Inner_Vector;
end Vector_Of_Vectors;
现在,您可以修改V_矩阵类型的每个向量元素的长度,以及向V_矩阵添加更多向量元素

下面是实例化向量包中的向量包的一个小示例:

with Ada.Containers.Vectors;
with Vector_Of_Vectors;
with Ada.Text_IO; use Ada.Text_IO;
use Ada.Containers;

procedure Main is
   package Int_Vector is new Ada.Containers.Vectors(Index_Type => Natural,
                                                    Element_Type => Integer);
   use Int_Vector;
   
   package Int_Matrix is new Vector_Of_Vectors(Index_Type   => Natural,
                                               inner_vector => Int_Vector);
   use Int_Matrix;
   
   Temp_Vect : Int_Vector.Vector;
   Temp_Mat  : V_Matrix.Vector;
begin

   Temp_Vect := Int_Vector.Empty_Vector;
   for I in 1..5 loop
      Temp_Vect.append(I);
   end loop;
   
   Temp_Mat.Append(Temp_Vect);
    
   temp_Vect := Int_Vector.Empty_Vector;
    
   for I in 15..25 loop
      Temp_Vect.append(I);
   end loop;
   Temp_Mat.Append(Temp_Vect);
     
   for V of Temp_Mat loop
      for I of V loop
         Put(I'Image);
      end loop;
      New_Line;
   end loop;
end Main;

下面是一个动态自调整二维阵列的可能解决方案。用法:

package Rect is new Rectangular (Element => Float, Default => 0.0);
use Rect;
Map : Rect.Matrix;
...
Map(-25, 97) := 42.0;
如果每增加一次大小,重新分配底层数组的成本将是不可接受的,因此包分配的资源略多于减少重新分配所需的资源

示例Main不断扩展数组,直到堆耗尽,并记录每次重新分配的时间。我对编译代码的速度感到惊喜,重新分配1_000 X 1_000数组1_000_000个元素只需5毫秒:

以下是在以下计算机上运行的输出:

存储错误与预期一样,我有32Gb内存

这是我在《美国残疾人法案》中的第一次尝试,欢迎评论

main.ads

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Assertions; use Ada.Assertions;
with Rectangular;

procedure Main is
    
    subtype Element is Float;
    
    Default_Value : Element := 42.0;
    
    package Rect is new Rectangular (Element => Element, Default => Default_Value);
    use Rect;
    Map : Rect.Matrix;
    
begin
    declare -- warmup, ensure values get set and defaults are applied
    begin
        Map (0, 0) := 2.3;
        Map (10, 10) := Map (0, 0) + 1.0;
        Assert (Map (0, 0) = 2.3);
        Assert (Map (10, 10) = 3.3);
        Assert (Map (5, 5) = Default_Value);
    end;
    
    declare -- Exercise hard to get reallocation timings
        Bytes           : Long_Long_Integer;
        MBytes          : Long_Long_Integer;
        ILong           : Long_Long_Integer;
        Current, Should : Element;
    begin
        for I in 0 .. 100_000 loop

            Map (I, I) := Element (I * 3);
            
            if I mod 10_000 = 0 then -- occasionally
                
                -- Check every value. On diagonal=3*, Off diagonal=Default_Value
                for Row in 0 .. I loop
                    for Col in 0 .. I loop
                        Current := Map (Row, Col );
                        if Row = Col then
                            Should := Element (Row * 3);
                        else
                            Should := Default_Value;
                        end if;
                        Assert (Current = Should);
                    end loop;
                end loop;
                
                -- Show progress
                ILong := Long_Long_Integer (I);
                Bytes := Ilong * Ilong * Long_Long_Integer (Element'Size) / 8;
                MBytes := Bytes / 2 ** 20;
                Put_Line (I'Image & " X " & I'Image & " is " & MBytes'Image & "Mb");
            end if;
        end loop;
    end;
end Main;
矩形广告

generic
    type Value_Type is private;

package Rectangular is
    
    function Get ( Row, Col : Integer) return Value_Type;
    procedure Set ( Row, Col : Integer; Value : Value_Type);
    
private
    type Matrix is array (Integer range <>, Integer range <>) of aliased Value_Type;
    
    Item : access Matrix;
    
end Rectangular;
generic
    type Element is private;
    Default : Element;

package Rectangular is
-- Provides an X..Y matrix of Element, which can be used just like a 2D Array.
-- The bounds of the array adjust themselves to accomodate requested indexes.
-- Rule-of-thumb: ~5 millseconds to re-allocate an array of 1'000'000 (1'000 x 1'000) entries. YMMV.
-- Usage:
--    package Rect is new Rectangular (Element => Float, Default => 0.0);
--    use Rect;
--    Map : Rect.Matrix;
--    ...
--    Map(-25, 97) := 42.0;
-- The bounds are now -25..0, 0..97, 2'548 elements, all 0.0 except -25,97 = 42.0
    
    type Matrix is tagged limited private
      with 
         Constant_Indexing => Get_Element,
         Variable_Indexing => Get_Reference;

    type Element_Access is access all Element;

    function Get_Element (M : in out Matrix; E : in Element_Access) return Element;

    function Get_Element (M : in out Matrix; Row, Col : in Integer) return Element;

    type Reference (R : access Element) is limited null record
      with Implicit_Dereference => R;

    function Get_Reference (M : in out Matrix; E : in Element_Access) return Reference;

    function Get_Reference (M : in out Matrix; Row, Col : in Integer) return Reference;

private
    type Backing is array (Integer range <>, Integer range <>) of Element;
    type Backing_Access is access Backing;
    type Matrix is tagged limited record
        Items : Backing_Access;
    end record;
end Rectangular;
A.adb:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Strings; use Ada.Strings;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Unchecked_Deallocation;
with Ada.Numerics.Generic_Elementary_Functions;

package body Rectangular is

    Demo : constant Boolean := True; -- Set to False once you've watched the demo
    
    function Create (Row_First, Row_Last, Col_First, Col_Last : Integer) return Backing_Access is
    -- Create a Backing array of Element'Access with (possibly negative) bounds
    begin
        return Answer :  Backing_Access :=
          new Backing (Row_First .. Row_Last, Col_First .. Col_Last)
        do
            for I in Row_First .. Row_Last loop
                for J in Col_First .. Col_Last loop
                    Answer (I, J) := Default;
                end loop;
            end loop;
        end return;
    end Create;
    
    function Multiplier (Bounds : Integer) return Float is
    -- From the bounds of an array, calculate a suitable, gentle increase
    -- Bounds | Log/(1+bounds,2) | 1/That | Increase
    --       1         1.0          1.000         1 
    --      10         3.5          0.289         3 
    --     100         6.7          0.150        15 
    --   1,000        10.0          0.100       100 
    --   5,000        12.3          0.081       407 
    --  10,000        13.3          0.075       753 
    --  25,000        14.6          0.068     1,711 
    -- 100,000        16.6          0.060     6,021 
    --
    -- So, for a matrix bound (row or column) that is 25'000, 
    -- the matrix will be resized to 25'000+1'711=26'711
    
        package Floats is new Ada.Numerics.Generic_Elementary_Functions (Float);
        Factor, Result : Float;
    begin
        Factor := Floats.Log (Float (1 + Bounds), 2.0);
        Result := 1.0 + 1.0 / Factor;
        -- Put_Line (Bounds'Image & ' ' & Factor'Image & ' ' & Result'Image);
        return Result;
    end Multiplier;
    
    procedure Free is new Ada.Unchecked_Deallocation (Backing, Backing_Access);
    -- Release a Backing.
    -- We know that this is safe, as they are private and only *we* can allocate them
    
    procedure Adjust_Bounds (M : in out Matrix; Row, Col : in Integer) is
    -- Check to see if Row-Col is within the current bounds.
    -- If not, enlarge the Backing to accomodate said Row-Col
    begin
        if M.Items = null then -- auto-initialise
            M.Items := Create (Row, Row, Col, Col);
        end if;
            
        if Row >= M.Items'First (1) and Row <= M.Items'Last (1) and
          Col >= M.Items'First (2) and Col <= M.Items'Last (2) then
            return; -- In bounds, all is well
        end if;
        
        declare
            Enlarged                       : Backing_Access;
            Row_First, Row_Last            : Integer;
            Col_First, Col_Last            : Integer;
            Row_Range, Col_Range           : Integer;
            Row_Multiplier, Col_Multiplier : Float;
            Start_Time, End_Time           : Time;
        
        begin
            if Demo then
                Start_Time := Clock;
            end if;
            Row_First := M.Items'First (1);
            Row_Last := M.Items'Last (1);
            Row_Range := Row_Last - Row_First + 1;
            Row_Multiplier := Multiplier (Row_Range);
        
            Col_First := M.Items'First (2);
            Col_Last := M.Items'Last (2);
            Col_Range := Col_Last - Col_First + 1;
            Col_Multiplier := Multiplier (Col_Range); 

            -- Integer'Min because the requested index may be further out than our conservative expansion multiplier
            if Row < Row_First then
                Row_First := Integer'Min (Row, Row_First - Integer (Float (Row_Range) * Row_Multiplier));
            elsif Row > Row_Last then
                Row_Last := Integer'Max (Row, Row_Last + Integer (Float (Row_Range) * Row_Multiplier));
            end if;
        
        
            if Col < Col_First then
                Col_First := Integer'Min (Col, Col_First - Integer (Float (Col_Range) * Col_Multiplier));
            elsif Col > Col_Last then
                Col_Last := Integer'Max (Col, Col_Last + Integer (Float (Col_Range) * Col_Multiplier));
            end if;

            Enlarged := Create (Row_First, Row_Last, Col_First, Col_Last);

            -- Copy old to new
            for R in M.Items'Range (1) loop
                for C in M.Items'Range (2) loop
                    Enlarged (R, C) := M.Items (R, C);
                end loop;
            end loop;
        
            Free (M.Items);
            M.Items := Enlarged;
            
            -- just for demonstration
            if Demo then
                declare
                    Seconds : Duration;
                    Size    : Long_Long_Integer := Long_Long_Integer (Row_Range) * Long_Long_Integer (Col_Range);
                begin
                    End_Time := Clock;
                    Seconds := End_Time - Start_Time;
                    Row_Range := Row_Last - Row_First + 1;
                    Col_Range := Col_Last - Col_First + 1;
                    Put_Line ("Resized to " & Row_First'Image & ".." & Trim (Row_Last'Image, Left) & ',' & 
                      Col_First'Image & ".." & Trim (Col_Last'Image, Left) & 
                      " = " & Size'Image & " entries in " & Duration'Image (Seconds) & " s");
                end;
            end if;
        end;
        
    end Adjust_Bounds;
    
    function Get_Reference (M : in out Matrix; E : in Element_Access) return Reference is
      (Reference'(R => E));

    function Get_Element (M : in out Matrix; E : in Element_Access) return Element is
      (M (E));

    function Get_Element (M : in out Matrix; Row, Col : in Integer) return Element is
        Result : Element;
    begin
        Adjust_Bounds (M, Row, Col);
        Result := M.Items (Row, Col);
        return Result;
    end Get_Element;

    function Get_Reference (M : in out Matrix; Row, Col : in Integer) return Reference is
    begin
        Adjust_Bounds (M, Row, Col);
        -- Unrestricted_Access is wicked, but we know what we're doing and it's the only way
        return Answer : Reference :=
          Reference'(R => M.Items ( Row, Col)'Unrestricted_Access);
    end Get_Reference;
    
end Rectangular;

下面是一个动态自调整二维阵列的可能解决方案。用法:

package Rect is new Rectangular (Element => Float, Default => 0.0);
use Rect;
Map : Rect.Matrix;
...
Map(-25, 97) := 42.0;
如果每增加一次大小,重新分配底层数组的成本将是不可接受的,因此包分配的资源略多于减少重新分配所需的资源

示例Main不断扩展数组,直到堆耗尽,并记录每次重新分配的时间。我对编译代码的速度感到惊喜,重新分配1_000 X 1_000数组1_000_000个元素只需5毫秒:

以下是在以下计算机上运行的输出:

存储错误与预期一样,我有32Gb内存

这是我在《美国残疾人法案》中的第一次尝试,欢迎评论

main.ads

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Assertions; use Ada.Assertions;
with Rectangular;

procedure Main is
    
    subtype Element is Float;
    
    Default_Value : Element := 42.0;
    
    package Rect is new Rectangular (Element => Element, Default => Default_Value);
    use Rect;
    Map : Rect.Matrix;
    
begin
    declare -- warmup, ensure values get set and defaults are applied
    begin
        Map (0, 0) := 2.3;
        Map (10, 10) := Map (0, 0) + 1.0;
        Assert (Map (0, 0) = 2.3);
        Assert (Map (10, 10) = 3.3);
        Assert (Map (5, 5) = Default_Value);
    end;
    
    declare -- Exercise hard to get reallocation timings
        Bytes           : Long_Long_Integer;
        MBytes          : Long_Long_Integer;
        ILong           : Long_Long_Integer;
        Current, Should : Element;
    begin
        for I in 0 .. 100_000 loop

            Map (I, I) := Element (I * 3);
            
            if I mod 10_000 = 0 then -- occasionally
                
                -- Check every value. On diagonal=3*, Off diagonal=Default_Value
                for Row in 0 .. I loop
                    for Col in 0 .. I loop
                        Current := Map (Row, Col );
                        if Row = Col then
                            Should := Element (Row * 3);
                        else
                            Should := Default_Value;
                        end if;
                        Assert (Current = Should);
                    end loop;
                end loop;
                
                -- Show progress
                ILong := Long_Long_Integer (I);
                Bytes := Ilong * Ilong * Long_Long_Integer (Element'Size) / 8;
                MBytes := Bytes / 2 ** 20;
                Put_Line (I'Image & " X " & I'Image & " is " & MBytes'Image & "Mb");
            end if;
        end loop;
    end;
end Main;
矩形广告

generic
    type Value_Type is private;

package Rectangular is
    
    function Get ( Row, Col : Integer) return Value_Type;
    procedure Set ( Row, Col : Integer; Value : Value_Type);
    
private
    type Matrix is array (Integer range <>, Integer range <>) of aliased Value_Type;
    
    Item : access Matrix;
    
end Rectangular;
generic
    type Element is private;
    Default : Element;

package Rectangular is
-- Provides an X..Y matrix of Element, which can be used just like a 2D Array.
-- The bounds of the array adjust themselves to accomodate requested indexes.
-- Rule-of-thumb: ~5 millseconds to re-allocate an array of 1'000'000 (1'000 x 1'000) entries. YMMV.
-- Usage:
--    package Rect is new Rectangular (Element => Float, Default => 0.0);
--    use Rect;
--    Map : Rect.Matrix;
--    ...
--    Map(-25, 97) := 42.0;
-- The bounds are now -25..0, 0..97, 2'548 elements, all 0.0 except -25,97 = 42.0
    
    type Matrix is tagged limited private
      with 
         Constant_Indexing => Get_Element,
         Variable_Indexing => Get_Reference;

    type Element_Access is access all Element;

    function Get_Element (M : in out Matrix; E : in Element_Access) return Element;

    function Get_Element (M : in out Matrix; Row, Col : in Integer) return Element;

    type Reference (R : access Element) is limited null record
      with Implicit_Dereference => R;

    function Get_Reference (M : in out Matrix; E : in Element_Access) return Reference;

    function Get_Reference (M : in out Matrix; Row, Col : in Integer) return Reference;

private
    type Backing is array (Integer range <>, Integer range <>) of Element;
    type Backing_Access is access Backing;
    type Matrix is tagged limited record
        Items : Backing_Access;
    end record;
end Rectangular;
A.adb:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Strings; use Ada.Strings;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Unchecked_Deallocation;
with Ada.Numerics.Generic_Elementary_Functions;

package body Rectangular is

    Demo : constant Boolean := True; -- Set to False once you've watched the demo
    
    function Create (Row_First, Row_Last, Col_First, Col_Last : Integer) return Backing_Access is
    -- Create a Backing array of Element'Access with (possibly negative) bounds
    begin
        return Answer :  Backing_Access :=
          new Backing (Row_First .. Row_Last, Col_First .. Col_Last)
        do
            for I in Row_First .. Row_Last loop
                for J in Col_First .. Col_Last loop
                    Answer (I, J) := Default;
                end loop;
            end loop;
        end return;
    end Create;
    
    function Multiplier (Bounds : Integer) return Float is
    -- From the bounds of an array, calculate a suitable, gentle increase
    -- Bounds | Log/(1+bounds,2) | 1/That | Increase
    --       1         1.0          1.000         1 
    --      10         3.5          0.289         3 
    --     100         6.7          0.150        15 
    --   1,000        10.0          0.100       100 
    --   5,000        12.3          0.081       407 
    --  10,000        13.3          0.075       753 
    --  25,000        14.6          0.068     1,711 
    -- 100,000        16.6          0.060     6,021 
    --
    -- So, for a matrix bound (row or column) that is 25'000, 
    -- the matrix will be resized to 25'000+1'711=26'711
    
        package Floats is new Ada.Numerics.Generic_Elementary_Functions (Float);
        Factor, Result : Float;
    begin
        Factor := Floats.Log (Float (1 + Bounds), 2.0);
        Result := 1.0 + 1.0 / Factor;
        -- Put_Line (Bounds'Image & ' ' & Factor'Image & ' ' & Result'Image);
        return Result;
    end Multiplier;
    
    procedure Free is new Ada.Unchecked_Deallocation (Backing, Backing_Access);
    -- Release a Backing.
    -- We know that this is safe, as they are private and only *we* can allocate them
    
    procedure Adjust_Bounds (M : in out Matrix; Row, Col : in Integer) is
    -- Check to see if Row-Col is within the current bounds.
    -- If not, enlarge the Backing to accomodate said Row-Col
    begin
        if M.Items = null then -- auto-initialise
            M.Items := Create (Row, Row, Col, Col);
        end if;
            
        if Row >= M.Items'First (1) and Row <= M.Items'Last (1) and
          Col >= M.Items'First (2) and Col <= M.Items'Last (2) then
            return; -- In bounds, all is well
        end if;
        
        declare
            Enlarged                       : Backing_Access;
            Row_First, Row_Last            : Integer;
            Col_First, Col_Last            : Integer;
            Row_Range, Col_Range           : Integer;
            Row_Multiplier, Col_Multiplier : Float;
            Start_Time, End_Time           : Time;
        
        begin
            if Demo then
                Start_Time := Clock;
            end if;
            Row_First := M.Items'First (1);
            Row_Last := M.Items'Last (1);
            Row_Range := Row_Last - Row_First + 1;
            Row_Multiplier := Multiplier (Row_Range);
        
            Col_First := M.Items'First (2);
            Col_Last := M.Items'Last (2);
            Col_Range := Col_Last - Col_First + 1;
            Col_Multiplier := Multiplier (Col_Range); 

            -- Integer'Min because the requested index may be further out than our conservative expansion multiplier
            if Row < Row_First then
                Row_First := Integer'Min (Row, Row_First - Integer (Float (Row_Range) * Row_Multiplier));
            elsif Row > Row_Last then
                Row_Last := Integer'Max (Row, Row_Last + Integer (Float (Row_Range) * Row_Multiplier));
            end if;
        
        
            if Col < Col_First then
                Col_First := Integer'Min (Col, Col_First - Integer (Float (Col_Range) * Col_Multiplier));
            elsif Col > Col_Last then
                Col_Last := Integer'Max (Col, Col_Last + Integer (Float (Col_Range) * Col_Multiplier));
            end if;

            Enlarged := Create (Row_First, Row_Last, Col_First, Col_Last);

            -- Copy old to new
            for R in M.Items'Range (1) loop
                for C in M.Items'Range (2) loop
                    Enlarged (R, C) := M.Items (R, C);
                end loop;
            end loop;
        
            Free (M.Items);
            M.Items := Enlarged;
            
            -- just for demonstration
            if Demo then
                declare
                    Seconds : Duration;
                    Size    : Long_Long_Integer := Long_Long_Integer (Row_Range) * Long_Long_Integer (Col_Range);
                begin
                    End_Time := Clock;
                    Seconds := End_Time - Start_Time;
                    Row_Range := Row_Last - Row_First + 1;
                    Col_Range := Col_Last - Col_First + 1;
                    Put_Line ("Resized to " & Row_First'Image & ".." & Trim (Row_Last'Image, Left) & ',' & 
                      Col_First'Image & ".." & Trim (Col_Last'Image, Left) & 
                      " = " & Size'Image & " entries in " & Duration'Image (Seconds) & " s");
                end;
            end if;
        end;
        
    end Adjust_Bounds;
    
    function Get_Reference (M : in out Matrix; E : in Element_Access) return Reference is
      (Reference'(R => E));

    function Get_Element (M : in out Matrix; E : in Element_Access) return Element is
      (M (E));

    function Get_Element (M : in out Matrix; Row, Col : in Integer) return Element is
        Result : Element;
    begin
        Adjust_Bounds (M, Row, Col);
        Result := M.Items (Row, Col);
        return Result;
    end Get_Element;

    function Get_Reference (M : in out Matrix; Row, Col : in Integer) return Reference is
    begin
        Adjust_Bounds (M, Row, Col);
        -- Unrestricted_Access is wicked, but we know what we're doing and it's the only way
        return Answer : Reference :=
          Reference'(R => M.Items ( Row, Col)'Unrestricted_Access);
    end Get_Reference;
    
end Rectangular;

只要使用Ada.Containers。不要使用匿名访问类型。@BrianDrummond Ada.Containers据我所知没有二维数组。我的用例是一个矩阵行、列:1字节状态的整数,表示地面上的一个区域;当机器人发现新地形时,地图必须展开。向量向量看起来很笨拙,映射将使用大量的存储空间,并带有指向1字节标志的指针。来自.Net,我可能完全误解了Ada的理念,欢迎使用任何指针。@egilhh我的代码的哪部分具有匿名访问类型?“访问矩阵”是匿名的吗?@smirkingman,是的,您拥有访问矩阵的所有地方都是匿名的,因此不同于其他地方,具有不同的访问级别。必须使用Ada.Containers。不要使用匿名访问类型。@BrianDrummond Ada.Containers据我所知没有二维数组。我的用例是一个矩阵行、列:1字节状态的整数,表示地面上的一个区域;当机器人发现新地形时,地图必须展开。向量向量看起来很笨拙,映射将使用大量的存储空间,并带有指向1字节标志的指针。来自.Net,我可能完全误解了Ada的理念,欢迎使用任何指针。@egilhh我的代码的哪部分具有匿名访问类型?“访问矩阵”是匿名的吗?@smirkingman,是的,你拥有访问矩阵的所有地方都是匿名的,因此不同于其他地方,具有不同的访问级别谢谢,我不知道“访问矩阵”是匿名的
我们现在很好用。我可以问你我是如何“解放”旧矩阵的吗?谢谢谢谢你,我不知道“访问矩阵”是匿名的。现在很好用。我可以问你我是如何“解放”旧矩阵的吗?谢谢谢谢,但是我该如何实例化它呢?package Rect是一个新的向量,它的向量索引类型为>Integer,内部向量为>Integer?整数值示例:package Int Vect是一个新的Ada.Containers.VectorIndex类型为>Natural,元素类型为>Integer;包int_矩阵是_向量整数的新向量,int_向量;谢谢你的跟进。不幸的是,向量在我的用例中似乎不起作用:假设我有一个向量,它是空的。我追加0,0并将其设置为占用:=False,因为我站在那里。我想知道5,5号牢房是否有人住我打算沿着1,1..5,5号牢房走。我不能说cell5,5=是否被占用,因为没有一个向量的值是1..5,1..5,所以我必须在引用cell5,5之前附加空条目1..5,1..5。或者我完全误解了什么?如果你使用一个数组,你将创建数组并用一个值初始化它的元素,比如False或True。然后,您将根据应用程序的规则修改数组中的每个元素。你可以对向量做同样的事情。当然,访问向量元素的语法比数组的语法更详细。谢谢,但是我该如何实例化它呢?package Rect是一个新的向量,它的向量索引类型为>Integer,内部向量为>Integer?整数值示例:package Int Vect是一个新的Ada.Containers.VectorIndex类型为>Natural,元素类型为>Integer;包int_矩阵是_向量整数的新向量,int_向量;谢谢你的跟进。不幸的是,向量在我的用例中似乎不起作用:假设我有一个向量,它是空的。我追加0,0并将其设置为占用:=False,因为我站在那里。我想知道5,5号牢房是否有人住我打算沿着1,1..5,5号牢房走。我不能说cell5,5=是否被占用,因为没有一个向量的值是1..5,1..5,所以我必须在引用cell5,5之前附加空条目1..5,1..5。或者我完全误解了什么?如果你使用一个数组,你将创建数组并用一个值初始化它的元素,比如False或True。然后,您将根据应用程序的规则修改数组中的每个元素。你可以对向量做同样的事情。诚然,访问向量元素的语法比访问数组的语法更详细。