------------------------------------------------------------------------------ -- -- -- 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-2024, 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 -- -- . -- -- -- -- 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;