111
|
1 ------------------------------------------------------------------------------
|
|
2 -- --
|
|
3 -- GNAT RUN-TIME COMPONENTS --
|
|
4 -- --
|
|
5 -- G N A T . B Y T E _ S W A P P I N G --
|
|
6 -- --
|
|
7 -- S p e c --
|
|
8 -- --
|
131
|
9 -- Copyright (C) 2006-2018, AdaCore --
|
111
|
10 -- --
|
|
11 -- GNAT is free software; you can redistribute it and/or modify it under --
|
|
12 -- terms of the GNU General Public License as published by the Free Soft- --
|
|
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
|
|
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
|
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
|
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
|
|
17 -- --
|
|
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
|
|
19 -- additional permissions described in the GCC Runtime Library Exception, --
|
|
20 -- version 3.1, as published by the Free Software Foundation. --
|
|
21 -- --
|
|
22 -- You should have received a copy of the GNU General Public License and --
|
|
23 -- a copy of the GCC Runtime Library Exception along with this program; --
|
|
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
|
25 -- <http://www.gnu.org/licenses/>. --
|
|
26 -- --
|
|
27 -- GNAT was originally developed by the GNAT team at New York University. --
|
|
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
29 -- --
|
|
30 ------------------------------------------------------------------------------
|
|
31
|
|
32 -- Simple routines for swapping the bytes of 16-, 32-, and 64-bit objects
|
|
33
|
|
34 -- The generic functions should be instantiated with types that are of a size
|
|
35 -- in bytes corresponding to the name of the generic. For example, a 2-byte
|
|
36 -- integer type would be compatible with Swapped2, 4-byte integer with
|
|
37 -- Swapped4, and so on. Failure to do so will result in a warning when
|
|
38 -- compiling the instantiation; this warning should be heeded. Ignoring this
|
|
39 -- warning can result in unexpected results.
|
|
40
|
|
41 -- An example of proper usage follows:
|
|
42
|
|
43 -- declare
|
|
44 -- type Short_Integer is range -32768 .. 32767;
|
|
45 -- for Short_Integer'Size use 16; -- for confirmation
|
|
46
|
|
47 -- X : Short_Integer := 16#7FFF#;
|
|
48
|
|
49 -- function Swapped is new Byte_Swapping.Swapped2 (Short_Integer);
|
|
50
|
|
51 -- begin
|
|
52 -- Put_Line (X'Img);
|
|
53 -- X := Swapped (X);
|
|
54 -- Put_Line (X'Img);
|
|
55 -- end;
|
|
56
|
|
57 -- Note that the generic actual types need not be scalars, but must be
|
|
58 -- 'definite' types. They can, for example, be constrained subtypes of
|
|
59 -- unconstrained array types as long as the size is correct. For instance,
|
|
60 -- a subtype of String with length of 4 would be compatible with the
|
|
61 -- Swapped4 generic:
|
|
62
|
|
63 -- declare
|
|
64 -- subtype String4 is String (1 .. 4);
|
|
65 -- function Swapped is new Byte_Swapping.Swapped4 (String4);
|
|
66 -- S : String4 := "ABCD";
|
|
67 -- for S'Alignment use 4;
|
|
68 -- begin
|
|
69 -- Put_Line (S);
|
|
70 -- S := Swapped (S);
|
|
71 -- Put_Line (S);
|
|
72 -- end;
|
|
73
|
|
74 -- Similarly, a constrained array type is also acceptable:
|
|
75
|
|
76 -- declare
|
|
77 -- type Mask is array (0 .. 15) of Boolean;
|
|
78 -- for Mask'Alignment use 2;
|
|
79 -- for Mask'Component_Size use Boolean'Size;
|
|
80 -- X : Mask := (0 .. 7 => True, others => False);
|
|
81 -- function Swapped is new Byte_Swapping.Swapped2 (Mask);
|
|
82 -- begin
|
|
83 -- ...
|
|
84 -- X := Swapped (X);
|
|
85 -- ...
|
|
86 -- end;
|
|
87
|
|
88 -- A properly-sized record type will also be acceptable, and so forth
|
|
89
|
|
90 -- However, as described, a size mismatch must be avoided. In the following we
|
|
91 -- instantiate one of the generics with a type that is too large. The result
|
|
92 -- of the function call is undefined, such that assignment to an object can
|
|
93 -- result in garbage values.
|
|
94
|
|
95 -- Wrong: declare
|
|
96 -- subtype String16 is String (1 .. 16);
|
|
97
|
|
98 -- function Swapped is new Byte_Swapping.Swapped8 (String16);
|
|
99 -- -- Instantiation generates a compiler warning about
|
|
100 -- -- mismatched sizes
|
|
101
|
|
102 -- S : String16;
|
|
103
|
|
104 -- begin
|
|
105 -- S := "ABCDEFGHDEADBEEF";
|
|
106 --
|
|
107 -- Put_Line (S);
|
|
108 --
|
|
109 -- -- the following assignment results in garbage in S after the
|
|
110 -- -- first 8 bytes
|
|
111 --
|
|
112 -- S := Swapped (S);
|
|
113 --
|
|
114 -- Put_Line (S);
|
|
115 -- end Wrong;
|
|
116
|
|
117 -- When the size of the type is larger than 8 bytes, the use of the non-
|
|
118 -- generic procedures is an alternative because no function result is
|
|
119 -- involved; manipulation of the object is direct.
|
|
120
|
|
121 -- The procedures are passed the address of an object to manipulate. They will
|
|
122 -- swap the first N bytes of that object corresponding to the name of the
|
|
123 -- procedure. For example:
|
|
124
|
|
125 -- declare
|
|
126 -- S2 : String := "AB";
|
|
127 -- for S2'Alignment use 2;
|
|
128 -- S4 : String := "ABCD";
|
|
129 -- for S4'Alignment use 4;
|
|
130 -- S8 : String := "ABCDEFGH";
|
|
131 -- for S8'Alignment use 8;
|
|
132
|
|
133 -- begin
|
|
134 -- Swap2 (S2'Address);
|
|
135 -- Put_Line (S2);
|
|
136
|
|
137 -- Swap4 (S4'Address);
|
|
138 -- Put_Line (S4);
|
|
139
|
|
140 -- Swap8 (S8'Address);
|
|
141 -- Put_Line (S8);
|
|
142 -- end;
|
|
143
|
|
144 -- If an object of a type larger than N is passed, the remaining bytes of the
|
|
145 -- object are undisturbed. For example:
|
|
146
|
|
147 -- declare
|
|
148 -- subtype String16 is String (1 .. 16);
|
|
149
|
|
150 -- S : String16;
|
|
151 -- for S'Alignment use 8;
|
|
152
|
|
153 -- begin
|
|
154 -- S := "ABCDEFGHDEADBEEF";
|
|
155 -- Put_Line (S);
|
|
156 -- Swap8 (S'Address);
|
|
157 -- Put_Line (S);
|
|
158 -- end;
|
|
159
|
|
160 with System;
|
|
161
|
|
162 package GNAT.Byte_Swapping is
|
|
163 pragma Pure;
|
|
164
|
|
165 -- NB: all the routines in this package treat the application objects as
|
|
166 -- unsigned (modular) types of a size in bytes corresponding to the routine
|
|
167 -- name. For example, the generic function Swapped2 manipulates the object
|
|
168 -- passed to the formal parameter Input as a value of an unsigned type that
|
|
169 -- is 2 bytes long. Therefore clients are responsible for the compatibility
|
|
170 -- of application types manipulated by these routines and these modular
|
|
171 -- types, in terms of both size and alignment. This requirement applies to
|
|
172 -- the generic actual type passed to the generic formal type Item in the
|
|
173 -- generic functions, as well as to the type of the object implicitly
|
|
174 -- designated by the address passed to the non-generic procedures. Use of
|
|
175 -- incompatible types can result in implementation- defined effects.
|
|
176
|
|
177 generic
|
|
178 type Item is limited private;
|
|
179 function Swapped2 (Input : Item) return Item;
|
|
180 -- Return the 2-byte value of Input with the bytes swapped
|
|
181
|
|
182 generic
|
|
183 type Item is limited private;
|
|
184 function Swapped4 (Input : Item) return Item;
|
|
185 -- Return the 4-byte value of Input with the bytes swapped
|
|
186
|
|
187 generic
|
|
188 type Item is limited private;
|
|
189 function Swapped8 (Input : Item) return Item;
|
|
190 -- Return the 8-byte value of Input with the bytes swapped
|
|
191
|
|
192 procedure Swap2 (Location : System.Address);
|
|
193 -- Swap the first 2 bytes of the object starting at the address specified
|
|
194 -- by Location.
|
|
195
|
|
196 procedure Swap4 (Location : System.Address);
|
|
197 -- Swap the first 4 bytes of the object starting at the address specified
|
|
198 -- by Location.
|
|
199
|
|
200 procedure Swap8 (Location : System.Address);
|
|
201 -- Swap the first 8 bytes of the object starting at the address specified
|
|
202 -- by Location.
|
|
203
|
|
204 pragma Inline (Swap2, Swap4, Swap8, Swapped2, Swapped4, Swapped8);
|
|
205
|
|
206 end GNAT.Byte_Swapping;
|