Read the second. This is more on point.
In the following implementation of a linked list, how can we get “discriminant check failed” for the current.all assignment statement inside the loop. But Block is mutable and I always do whole assignments so I don’t understand.
The idea was to create the last piece first, whose length is between 1 and the chosen chunk size, and if that wasn’t the whole string, insert the rest of the links from the start of the string. The “hoops” and “remainder” variable’s valuess are correct. I must be missing something.
pragma Ada_2022;
pragma extensions_allowed (all);
with Ada.Text_IO; use Ada.Text_IO;
procedure Test is
size_chunk : constant := 10;
subtype Limit is Natural range 0..size_chunk;
type Block (Length: Limit := size_chunk) is record
Value: String (1..Length);
Next: access Block;
end record;
type Vstring is record
First: access Block;
Length: Natural := 0;
end record;
function Create (Str : String) return Vstring is
remainder : constant String := Str(Str'Last + 1 - (Str'Length mod size_chunk) .. Str'Last);
Hoops : constant Natural := Str'Length / size_chunk;
is_null : constant Boolean := Str'Length = 0;
Vstr : Vstring := (if is_null then (null,0)
else (new Block'(remainder'Length, remainder, null), Str'Length));
current : access Block := Vstr.first;
begin
for I in 1..Hoops loop
current.all := (size_chunk, Str(Str'First + (I - 1) * size_chunk .. Str'First + I * size_chunk - 1), @); -- HHHHHHHEEEEERE
current := current.next;
end loop;
return Vstr;
end Create;
A: Vstring := create ("AAAAAAAAAAAAAAAAAAA");
begin
null;
end;
I thought in the HHHEEERRREEE line it should end with @'Access
, but that gives error: access-to-variable designates constant
.
Using ’Unrestricted_Access
(best avoided if possible, but in the interests of exploring the problem…), it turns out that Current’Length
is 9 for I = 1
, so writing size_chunk
to it will violate the discriminant check.
Ahhh I finally did it. Now that’s elegance. No needless allocation, no special case failure.
I hate indirections and pointers, this is nearly impossible to get your head around.
function Create (Str : String) return Vstring is
remainder : constant String := Str(Str'Last + 1 - (Str'Length mod size_chunk) .. Str'Last);
begin
return (null, 0) when Str'Length = 0;
declare
Vstr : Vstring := (new Block'(remainder'Length, remainder, null), Str'Length);
temp: aliased Block := (0,"",null);
first, current : access Block := temp'Access;
begin
for I in 1..(Str'Length - remainder'Length) / size_chunk loop
current.next := new Block'(size_chunk, Str(Str'First + (I - 1) * size_chunk .. Str'First + I * size_chunk - 1), null);
current := current.next;
end loop;
current.next := new Block'(remainder'Length, remainder, null);
vstr.first := first.next;
return Vstr;
end;
end Create;
as for the above, first thing it seems that because @ is a constant view of the target you must use access to constant types even if if nothing is assignated during that statement. I wonder if this rule could be changed, since what it points to isn’t necessarily a constant.
I don’t understand what fails though.
at first iteration, lower bound of the substring is 1, upper is 10. it still causes “length check failed”.
replace the loop with
for I in 1..Hoops loop
put_line("length = " & Integer'Image (Str'First + (I - 1) * size_chunk - Str'First + I * size_chunk - 1));
put_line("size_chunk = " & Integer'Image (size_chunk));
put_line("bottom = " & Integer'Image (Str'First + (I - 1) * size_chunk));
put_line("top = " & Integer'Image (Str'First + I * size_chunk - 1));
current.all := (size_chunk - 1, Str(Str'First + (I - 1) * size_chunk .. Str'First + I * size_chunk - 1), @'Unrestricted_Access); -- HHHHHHHEEEEERE
current := current.next;
end loop;
How is this length calculation even done ? It should be top-bottom + 1, no ?