| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT RUN-TIME COMPONENTS -- |
| -- -- |
| -- G N A T . B Y T E _ S W A P P I N G -- |
| -- -- |
| -- S p e c -- |
| -- -- |
| -- Copyright (C) 2006-2022, AdaCore -- |
| -- -- |
| -- GNAT is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. -- |
| -- -- |
| -- As a special exception under Section 7 of GPL version 3, you are granted -- |
| -- additional permissions described in the GCC Runtime Library Exception, -- |
| -- version 3.1, as published by the Free Software Foundation. -- |
| -- -- |
| -- You should have received a copy of the GNU General Public License and -- |
| -- a copy of the GCC Runtime Library Exception along with this program; -- |
| -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- |
| -- <http://www.gnu.org/licenses/>. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| -- Simple routines for swapping the bytes of 16-, 32-, and 64-bit objects |
| |
| -- The generic functions should be instantiated with types that are of a size |
| -- in bytes corresponding to the name of the generic. For example, a 2-byte |
| -- integer type would be compatible with Swapped2, 4-byte integer with |
| -- Swapped4, and so on. Failure to do so will result in a warning when |
| -- compiling the instantiation; this warning should be heeded. Ignoring this |
| -- warning can result in unexpected results. |
| |
| -- An example of proper usage follows: |
| |
| -- declare |
| -- type Short_Integer is range -32768 .. 32767; |
| -- for Short_Integer'Size use 16; -- for confirmation |
| |
| -- X : Short_Integer := 16#7FFF#; |
| |
| -- function Swapped is new Byte_Swapping.Swapped2 (Short_Integer); |
| |
| -- begin |
| -- Put_Line (X'Img); |
| -- X := Swapped (X); |
| -- Put_Line (X'Img); |
| -- end; |
| |
| -- Note that the generic actual types need not be scalars, but must be |
| -- 'definite' types. They can, for example, be constrained subtypes of |
| -- unconstrained array types as long as the size is correct. For instance, |
| -- a subtype of String with length of 4 would be compatible with the |
| -- Swapped4 generic: |
| |
| -- declare |
| -- subtype String4 is String (1 .. 4); |
| -- function Swapped is new Byte_Swapping.Swapped4 (String4); |
| -- S : String4 := "ABCD"; |
| -- for S'Alignment use 4; |
| -- begin |
| -- Put_Line (S); |
| -- S := Swapped (S); |
| -- Put_Line (S); |
| -- end; |
| |
| -- Similarly, a constrained array type is also acceptable: |
| |
| -- declare |
| -- type Mask is array (0 .. 15) of Boolean; |
| -- for Mask'Alignment use 2; |
| -- for Mask'Component_Size use Boolean'Size; |
| -- X : Mask := (0 .. 7 => True, others => False); |
| -- function Swapped is new Byte_Swapping.Swapped2 (Mask); |
| -- begin |
| -- ... |
| -- X := Swapped (X); |
| -- ... |
| -- end; |
| |
| -- A properly-sized record type will also be acceptable, and so forth |
| |
| -- However, as described, a size mismatch must be avoided. In the following we |
| -- instantiate one of the generics with a type that is too large. The result |
| -- of the function call is undefined, such that assignment to an object can |
| -- result in garbage values. |
| |
| -- Wrong: declare |
| -- subtype String16 is String (1 .. 16); |
| |
| -- function Swapped is new Byte_Swapping.Swapped8 (String16); |
| -- -- Instantiation generates a compiler warning about |
| -- -- mismatched sizes |
| |
| -- S : String16; |
| |
| -- begin |
| -- S := "ABCDEFGHDEADBEEF"; |
| -- |
| -- Put_Line (S); |
| -- |
| -- -- the following assignment results in garbage in S after the |
| -- -- first 8 bytes |
| -- |
| -- S := Swapped (S); |
| -- |
| -- Put_Line (S); |
| -- end Wrong; |
| |
| -- When the size of the type is larger than 8 bytes, the use of the non- |
| -- generic procedures is an alternative because no function result is |
| -- involved; manipulation of the object is direct. |
| |
| -- The procedures are passed the address of an object to manipulate. They will |
| -- swap the first N bytes of that object corresponding to the name of the |
| -- procedure. For example: |
| |
| -- declare |
| -- S2 : String := "AB"; |
| -- for S2'Alignment use 2; |
| -- S4 : String := "ABCD"; |
| -- for S4'Alignment use 4; |
| -- S8 : String := "ABCDEFGH"; |
| -- for S8'Alignment use 8; |
| |
| -- begin |
| -- Swap2 (S2'Address); |
| -- Put_Line (S2); |
| |
| -- Swap4 (S4'Address); |
| -- Put_Line (S4); |
| |
| -- Swap8 (S8'Address); |
| -- Put_Line (S8); |
| -- end; |
| |
| -- If an object of a type larger than N is passed, the remaining bytes of the |
| -- object are undisturbed. For example: |
| |
| -- declare |
| -- subtype String16 is String (1 .. 16); |
| |
| -- S : String16; |
| -- for S'Alignment use 8; |
| |
| -- begin |
| -- S := "ABCDEFGHDEADBEEF"; |
| -- Put_Line (S); |
| -- Swap8 (S'Address); |
| -- Put_Line (S); |
| -- end; |
| |
| with System; |
| |
| package GNAT.Byte_Swapping is |
| pragma Pure; |
| |
| -- NB: all the routines in this package treat the application objects as |
| -- unsigned (modular) types of a size in bytes corresponding to the routine |
| -- name. For example, the generic function Swapped2 manipulates the object |
| -- passed to the formal parameter Input as a value of an unsigned type that |
| -- is 2 bytes long. Therefore clients are responsible for the compatibility |
| -- of application types manipulated by these routines and these modular |
| -- types, in terms of both size and alignment. This requirement applies to |
| -- the generic actual type passed to the generic formal type Item in the |
| -- generic functions, as well as to the type of the object implicitly |
| -- designated by the address passed to the non-generic procedures. Use of |
| -- incompatible types can result in implementation- defined effects. |
| |
| generic |
| type Item is limited private; |
| function Swapped2 (Input : Item) return Item; |
| -- Return the 2-byte value of Input with the bytes swapped |
| |
| generic |
| type Item is limited private; |
| function Swapped4 (Input : Item) return Item; |
| -- Return the 4-byte value of Input with the bytes swapped |
| |
| generic |
| type Item is limited private; |
| function Swapped8 (Input : Item) return Item; |
| -- Return the 8-byte value of Input with the bytes swapped |
| |
| procedure Swap2 (Location : System.Address); |
| -- Swap the first 2 bytes of the object starting at the address specified |
| -- by Location. |
| |
| procedure Swap4 (Location : System.Address); |
| -- Swap the first 4 bytes of the object starting at the address specified |
| -- by Location. |
| |
| procedure Swap8 (Location : System.Address); |
| -- Swap the first 8 bytes of the object starting at the address specified |
| -- by Location. |
| |
| pragma Inline (Swap2, Swap4, Swap8, Swapped2, Swapped4, Swapped8); |
| |
| end GNAT.Byte_Swapping; |