1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 | -- part of AdaYaml, (c) 2017 Felix Krause
-- released under the terms of the MIT license, see the file "copying.txt"
with Ada.Strings.Hash;
with System;
with Yaml.Dom.Node_Memory;
package body Yaml.Dom.Node is
use type Text.Reference;
use type Ada.Containers.Hash_Type;
use type Count_Type;
use type System.Address;
function "=" (Left, Right : Instance) return Boolean is
Memory : Node_Memory.Pair_Instance;
function Equal (Left, Right : not null access Instance) return Boolean;
function Equal (Left, Right : Sequence_Data.Instance) return Boolean is
Cur_Left, Cur_Right : Sequence_Data.Cursor;
begin
if Left.Length /= Right.Length then
return False;
end if;
Cur_Left := Left.First;
Cur_Right := Right.First;
while Sequence_Data.Has_Element (Cur_Left) loop
if not Equal (Left.Element (Cur_Left).Value.Data,
Right.Element (Cur_Right).Value.Data) then
return False;
end if;
Cur_Left := Sequence_Data.Next (Cur_Left);
Cur_Right := Sequence_Data.Next (Cur_Right);
end loop;
return True;
end Equal;
function Equal (Left, Right : Mapping_Data.Instance) return Boolean is
Cur_Left, Cur_Right : Mapping_Data.Cursor;
begin
if Left.Length /= Right.Length then
return False;
end if;
Cur_Left := Left.First;
while Mapping_Data.Has_Element (Cur_Left) loop
Cur_Right := Right.Find (Mapping_Data.Key (Cur_Left));
if not Mapping_Data.Has_Element (Cur_Right) or else
not Equal (Mapping_Data.Value (Cur_Left).Data,
Mapping_Data.Value (Cur_Right).Data) then
return False;
end if;
Cur_Left := Mapping_Data.Next (Cur_Left);
end loop;
return True;
end Equal;
function Equal (Left, Right : not null access Instance) return Boolean is
Visited : Boolean;
begin
if Left.all'Address = Right.all'Address then
return True;
else
Memory.Visit (Left, Right, Visited);
if Visited then
return True;
elsif Left.Kind = Right.Kind and then Left.Tag = Right.Tag then
case Left.Kind is
when Scalar => return Left.Content = Right.Content;
when Sequence => return Equal (Left.Items, Right.Items);
when Mapping => return Equal (Left.Pairs, Right.Pairs);
end case;
else
return False;
end if;
end if;
end Equal;
begin
return Equal (Left'Unrestricted_Access, Right'Unrestricted_Access);
end "=";
function Hash (Object : Instance) return Ada.Containers.Hash_Type is
-- for efficiency reasons, the hash of a collection node is not
-- calculated recursively. Instead, only the content of the node and the
-- types and number of its children (and their content for scalars) is
-- taken into account. this suffices as hash function as long as the
-- objects used as keys do not get too large.
begin
if Object.Kind = Scalar then
return Object.Content.Hash;
else
declare
Ret : Ada.Containers.Hash_Type :=
Ada.Strings.Hash (Object.Kind'Img);
procedure Visit (Prefix : String;
Cur : not null access Node.Instance) is
begin
case Cur.Kind is
when Scalar => Ret := Ret * Cur.Content.Hash;
when Sequence =>
Ret := Ret * Ada.Strings.Hash
(Prefix & "Sequence" & Cur.Items.Length'Img);
when Mapping =>
Ret := Ret * Ada.Strings.Hash
(Prefix & "Mapping" & Cur.Pairs.Length'Img);
end case;
end Visit;
procedure Visit_Item (Cur : not null access Node.Instance) is
begin
Visit ("Item:", Cur);
end Visit_Item;
procedure Visit_Pair (Key, Value : not null access Node.Instance) is
begin
Visit ("Key:", Key);
Visit ("Value:", Value);
end Visit_Pair;
begin
if Object.Kind = Sequence then
Object.Items.Iterate (Visit_Item'Access);
else
Object.Pairs.Iterate (Visit_Pair'Access);
end if;
return Ret;
end;
end if;
end Hash;
end Yaml.Dom.Node;
|