FV3 Bundle
Endian_Utility.f90
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------
2 !M+
3 ! NAME:
4 ! Endian_Utility
5 !
6 ! PURPOSE:
7 ! Module containing functions to byte-swap intrinsic data types.
8 !
9 ! CATEGORY:
10 ! Utility
11 !
12 ! LANGUAGE:
13 ! Fortran-95
14 !
15 ! CALLING SEQUENCE:
16 ! USE Endian_Utility
17 !
18 ! MODULES:
19 ! Type_Kinds: Module to hold specification kinds for variable
20 ! declaration.
21 !
22 ! CONTAINS:
23 ! Big_Endian: Logical function that returns .TRUE. if platform
24 ! is big endian.
25 !
26 ! Swap_Endian: Function that byte-swaps input arguments.
27 !
28 ! INCLUDE FILES:
29 ! None.
30 !
31 ! EXTERNALS:
32 ! None.
33 !
34 ! COMMON BLOCKS:
35 ! None.
36 !
37 ! FILES ACCESSED:
38 ! None.
39 !
40 ! SIDE EFFECTS:
41 ! None.
42 !
43 ! RESTRICTIONS:
44 ! None.
45 !
46 ! CREATION HISTORY:
47 ! Written by: Paul van Delst, CIMSS/SSEC, 17-Mar-2000
48 ! paul.vandelst@ssec.wisc.edu
49 !
50 ! Copyright (C) 2000 Paul van Delst
51 !
52 ! This program is free software; you can redistribute it and/or
53 ! modify it under the terms of the GNU General Public License
54 ! as published by the Free Software Foundation; either version 2
55 ! of the License, or (at your option) any later version.
56 !
57 ! This program is distributed in the hope that it will be useful,
58 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
59 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 ! GNU General Public License for more details.
61 !
62 ! You should have received a copy of the GNU General Public License
63 ! along with this program; if not, write to the Free Software
64 ! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
65 !M-
66 !--------------------------------------------------------------------------------
67 
69 
70 
71  ! ----------
72  ! Module use
73  ! ----------
74 
75  USE type_kinds
76 
77 
78  ! ---------------------------
79  ! Disable all implicit typing
80  ! ---------------------------
81 
82  IMPLICIT NONE
83 
84 
85  ! ------------
86  ! Visibilities
87  ! ------------
88 
89  PRIVATE
90  PUBLIC :: big_endian
91  PUBLIC :: swap_endian
92 
93 
94  ! ------------------
95  ! Overload interface
96  ! ------------------
97 
98  INTERFACE swap_endian
99  MODULE PROCEDURE swap_short_integer
100  MODULE PROCEDURE swap_long_integer
101  MODULE PROCEDURE swap_llong_integer
102  MODULE PROCEDURE swap_single_float
103  MODULE PROCEDURE swap_double_float
104  MODULE PROCEDURE swap_single_complex
105  MODULE PROCEDURE swap_double_complex
106  END INTERFACE swap_endian
107 
108 
109 CONTAINS
110 
111 
112 !################################################################################
113 !################################################################################
114 !## ##
115 !## ## PUBLIC MODULE ROUTINES ## ##
116 !## ##
117 !################################################################################
118 !################################################################################
119 
120 !--------------------------------------------------------------------------------
121 !S+
122 ! NAME:
123 ! Big_Endian
124 !
125 ! PURPOSE:
126 ! Function to determine if current platform is big-endian.
127 !
128 ! CATEGORY:
129 ! Utility
130 !
131 ! LANGUAGE:
132 ! Fortran-95
133 !
134 ! CALLING SEQUENCE:
135 ! Result = Big_Endian()
136 !
137 ! INPUT ARGUMENTS:
138 ! None.
139 !
140 ! OPTIONAL INPUT ARGUMENTS:
141 ! None.
142 !
143 ! OUTPUT ARGUMENTS:
144 ! None.
145 !
146 ! OPTIONAL OUTPUT ARGUMENTS:
147 ! None.
148 !
149 ! FUNCTION RESULT:
150 ! Result: The return value is a logical value indicating whether
151 ! the current platform is big-endian or not
152 ! .TRUE. - it is a big-endian platform.
153 ! .FALSE. - it is NOT a big-endian platform.
154 ! UNITS: N/A
155 ! TYPE: LOGICAL
156 ! DIMENSION: Scalar
157 !
158 ! CALLS:
159 ! None.
160 !
161 ! CONTAINS:
162 ! None.
163 !
164 ! SIDE EFFECTS:
165 ! None
166 !
167 ! RESTRICTIONS:
168 ! None
169 !
170 ! PROCEDURE:
171 ! Uses the Fortran90/95 intrinsics TRANSFER and IACHAR to test
172 ! if a 2-byte integer (value 1) retains that value when
173 ! transferred to a single-byte character representation. If
174 ! it does, the platform is little-endian. If not, it is big-
175 ! endian. This method was suggested by Clive Page, University
176 ! of Leicester, UK.
177 !
178 ! EXAMPLE:
179 ! USE Endian_Utility
180 ! .....
181 ! WRITE( *, '( 5x, "Platform is " )', ADVANCE = 'NO' )
182 ! IF ( Big_Endian() ) THEN
183 ! WRITE( *, '( "big-endian." )' )
184 ! ELSE
185 ! WRITE( *, '( "litle-endian." )' )
186 ! END IF
187 !
188 !S-
189 !--------------------------------------------------------------------------------
190 
191  FUNCTION big_endian()
193 
194  ! ---------------
195  ! Local variables
196  ! ---------------
197 
198  INTEGER( Short ) :: source = 1_short
199 
200 
201  ! ------------
202  ! The function
203  ! ------------
204 
205  LOGICAL :: big_endian
206 
207 
208  ! ----------
209  ! Intrinsics
210  ! ----------
211 
212  INTRINSIC transfer, ichar
213 
214 
215  ! ----------------------------------
216  ! Initialise result to little-endian
217  ! ----------------------------------
218 
219  big_endian = .false.
220 
221 
222  ! ------------------------------------------------------------
223  ! Test for "endian-ness".
224  !
225  ! TRANSFER( source, 'a' ) returns a result with the physical
226  ! representation of the number 1, i.e. an integer, but
227  ! interpreted as a character (the type of 'a' - a character,
228  ! not the value, is what is important).
229  !
230  ! IACHAR returns the position of a character in the ASCII
231  ! collating sequence associated with the kind type parameter
232  ! of the character.
233  ! ------------------------------------------------------------
234 
235  IF ( iachar( transfer( source, 'a' ) ) == 0 ) big_endian = .true.
236 
237  END FUNCTION big_endian
238 
239 
240 
241 
242 
243 !--------------------------------------------------------------------------------
244 !S+
245 ! NAME:
246 ! Swap_Endian
247 !
248 ! PURPOSE:
249 ! Function to byte-swap input data.
250 !
251 ! CATEGORY:
252 ! Utility
253 !
254 ! LANGUAGE:
255 ! Fortran-95
256 !
257 ! CALLING SEQUENCE:
258 ! Result = Swap_Endian( Input )
259 !
260 ! INPUT ARGUMENTS:
261 ! Input: Data object to be byte swapped.
262 ! UNITS: N/A
263 ! TYPE: Any of the following:
264 ! INTEGER( Short )
265 ! INTEGER( Long ) [ == default integer]
266 ! INTEGER( LLong )
267 ! REAL( Single ) [ == default real]
268 ! REAL( Double )
269 ! COMPLEX( Single )
270 ! COMPLEX( Double )
271 ! DIMENSION: Scalar, or any allowed rank array.
272 ! ATTRIBUTES: INTENT( IN )
273 !
274 ! OPTIONAL INPUT ARGUMENTS:
275 ! None.
276 !
277 ! OUTPUT ARGUMENTS:
278 ! None.
279 !
280 ! OPTIONAL OUTPUT ARGUMENTS:
281 ! None.
282 !
283 ! FUNCTION RESULT:
284 ! Result: The return value is the byte swapped value
285 ! UNITS: N/A
286 ! TYPE: Same as Input
287 ! DIMENSION: Same as Input
288 !
289 ! CALLS:
290 ! None.
291 !
292 ! CONTAINS:
293 ! None.
294 !
295 ! SIDE EFFECTS:
296 ! None
297 !
298 ! RESTRICTIONS:
299 ! None.
300 !
301 ! PROCEDURE:
302 ! The TRANSFER intrinsic is used to rearrange the bytes by accessing
303 ! the data with a subscript triplet having a negative stride.
304 !
305 ! This method can be slow, not because of the TRANSFER function itself,
306 ! but the negative stride of the array access. It depends on the
307 ! quality of implementation.
308 !
309 ! The byte-swap for the complex data types are only slightly
310 ! different in that each half of the total number representation
311 ! in bytes is swapped rather than the whole thing (i.e. real and
312 ! imaginary are swapped separately).
313 !
314 !S-
315 !--------------------------------------------------------------------------------
316 
317  ELEMENTAL FUNCTION swap_short_integer ( Input ) RESULT ( Output )
319 
320  ! -------------------
321  ! Argument and result
322  ! -------------------
323 
324  INTEGER( Short ), INTENT( IN ) :: input
325  INTEGER( Short ) :: output
326 
327 
328  ! ----------------
329  ! Local parameters
330  ! ----------------
331 
332  INTEGER, PARAMETER :: n = n_bytes_short
333 
334 
335  ! ---------------
336  ! Local variables
337  ! ---------------
338 
339  INTEGER( Byte ), DIMENSION( N ) :: byte_equivalent
340 
341 
342  ! ------------------------------------------------
343  ! Byte swap the data. The extra step in the middle
344  ! is necessary for those compilers that can't
345  ! handle a negative strided input to TRANSFER
346  ! ------------------------------------------------
347 
348  byte_equivalent = transfer( input, byte_equivalent )
349  byte_equivalent = byte_equivalent( n:1:-1 )
350  output = transfer( byte_equivalent, output )
351 
352  END FUNCTION swap_short_integer
353 
354 
355  ELEMENTAL FUNCTION swap_long_integer ( Input ) RESULT ( Output )
357 
358  ! -------------------
359  ! Argument and result
360  ! -------------------
361 
362  INTEGER( Long ), INTENT( IN ) :: input
363  INTEGER( Long ) :: output
364 
365 
366  ! ----------------
367  ! Local parameters
368  ! ----------------
369 
370  INTEGER, PARAMETER :: n = n_bytes_long
371 
372 
373  ! ---------------
374  ! Local variables
375  ! ---------------
376 
377  INTEGER( Byte ), DIMENSION( N ) :: byte_equivalent
378 
379 
380  ! ------------------------------------------------
381  ! Byte swap the data. The extra step in the middle
382  ! is necessary for those compilers that can't
383  ! handle a negative strided input to TRANSFER
384  ! ------------------------------------------------
385 
386  byte_equivalent = transfer( input, byte_equivalent )
387  byte_equivalent = byte_equivalent( n:1:-1 )
388  output = transfer( byte_equivalent, output )
389 
390  END FUNCTION swap_long_integer
391 
392 
393  ELEMENTAL FUNCTION swap_llong_integer ( Input ) RESULT ( Output )
395 
396  ! -------------------
397  ! Argument and result
398  ! -------------------
399 
400  INTEGER( LLong ), INTENT( IN ) :: input
401  INTEGER( LLong ) :: output
402 
403 
404  ! ----------------
405  ! Local parameters
406  ! ----------------
407 
408  INTEGER, PARAMETER :: n = n_bytes_llong
409 
410 
411  ! ---------------
412  ! Local variables
413  ! ---------------
414 
415  INTEGER( Byte ), DIMENSION( N ) :: byte_equivalent
416 
417 
418  ! ------------------------------------------------
419  ! Byte swap the data. The extra step in the middle
420  ! is necessary for those compilers that can't
421  ! handle a negative strided input to TRANSFER
422  ! ------------------------------------------------
423 
424  byte_equivalent = transfer( input, byte_equivalent )
425  byte_equivalent = byte_equivalent( n:1:-1 )
426  output = transfer( byte_equivalent, output )
427 
428  END FUNCTION swap_llong_integer
429 
430 
431  ELEMENTAL FUNCTION swap_single_float ( Input ) RESULT ( Output )
433 
434  ! -------------------
435  ! Argument and result
436  ! -------------------
437 
438  REAL( Single ), INTENT( IN ) :: input
439  REAL( Single ) :: output
440 
441 
442  ! ----------------
443  ! Local parameters
444  ! ----------------
445 
446  INTEGER, PARAMETER :: n = n_bytes_single
447 
448 
449  ! ---------------
450  ! Local variables
451  ! ---------------
452 
453  INTEGER( Byte ), DIMENSION( N ) :: byte_equivalent
454 
455 
456  ! ------------------------------------------------
457  ! Byte swap the data. The extra step in the middle
458  ! is necessary for those compilers that can't
459  ! handle a negative strided input to TRANSFER
460  ! ------------------------------------------------
461 
462  byte_equivalent = transfer( input, byte_equivalent )
463  byte_equivalent = byte_equivalent( n:1:-1 )
464  output = transfer( byte_equivalent, output )
465 
466  END FUNCTION swap_single_float
467 
468 
469  ELEMENTAL FUNCTION swap_double_float ( Input ) RESULT ( Output )
471 
472  ! -------------------
473  ! Argument and result
474  ! -------------------
475 
476  REAL( Double ), INTENT( IN ) :: input
477  REAL( Double ) :: output
478 
479 
480  ! ----------------
481  ! Local parameters
482  ! ----------------
483 
484  INTEGER, PARAMETER :: n = n_bytes_double
485 
486 
487  ! ---------------
488  ! Local variables
489  ! ---------------
490 
491  INTEGER( Byte ), DIMENSION( N ) :: byte_equivalent
492 
493 
494  ! ------------------------------------------------
495  ! Byte swap the data. The extra step in the middle
496  ! is necessary for those compilers that can't
497  ! handle a negative strided input to TRANSFER
498  ! ------------------------------------------------
499 
500  byte_equivalent = transfer( input, byte_equivalent )
501  byte_equivalent = byte_equivalent( n:1:-1 )
502  output = transfer( byte_equivalent, output )
503 
504  END FUNCTION swap_double_float
505 
506 
507  ELEMENTAL FUNCTION swap_single_complex ( Input ) RESULT ( Output )
509 
510  ! -------------------
511  ! Argument and result
512  ! -------------------
513 
514  COMPLEX( Single ), INTENT( IN ) :: input
515  COMPLEX( Single ) :: output
516 
517 
518  ! ------------------
519  ! Byte-swap the data
520  ! ------------------
521 
522  output = cmplx( swap_endian( REAL( Input, Single ) ), & ! Real
523  swap_endian( REAL( AIMAG( Input ), Single ) ), & ! Imaginary
524  single )
525 
526  END FUNCTION swap_single_complex
527 
528 
529  ELEMENTAL FUNCTION swap_double_complex ( Input ) RESULT ( Output )
531 
532  ! -------------------
533  ! Argument and result
534  ! -------------------
535 
536  COMPLEX( Double ), INTENT( IN ) :: input
537  COMPLEX( Double ) :: output
538 
539 
540  ! ------------------
541  ! Byte-swap the data
542  ! ------------------
543 
544  output = cmplx( swap_endian( REAL( Input, Double ) ), & ! Real
545  swap_endian( REAL( AIMAG( Input ), Double ) ), & ! Imaginary
546  double )
547 
548 
549  END FUNCTION swap_double_complex
550 
551 END MODULE endian_utility
552 
553 
554 
555 !-------------------------------------------------------------------------------
556 ! -- MODIFICATION HISTORY --
557 !-------------------------------------------------------------------------------
558 !
559 ! $Id: Endian_Utility.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $
560 !
561 ! $Date: 2004/12/01 19:35:15 $
562 !
563 ! $Revision: 60152 $
564 !
565 ! $State: Exp $
566 !
567 ! $Name: $
568 !
569 ! $Log: Endian_Utility.f90,v $
570 ! Revision 2.3 2004/12/01 19:35:15 paulv
571 ! - Documentation errors corrected.
572 !
573 ! Revision 2.2 2004/08/17 14:36:24 paulv
574 ! - Changed the comment header for the actual byte-swapping code.
575 ! - Note the log message for the last update is incorrect - the negative
576 ! stride must be removed from the input argument to TRANSFER to prevent
577 ! run-time crashes when versions of the xlf 8.1 compiler are used.
578 !
579 ! Revision 2.1 2004/08/16 16:04:22 paulv
580 ! - Due to an IBM xlf compiler bug I changed
581 ! Output = TRANSFER( Byte_Equivalent( N:1:-1 ), Output )
582 ! to
583 ! Byte_Equivalent = Byte_Equivalent( N:1:-1 )
584 ! Output = TRANSFER( (Byte_Equivalent(N:1:-1), Output )
585 ! The negative stride triplet used in the input to TRANSFER was causing
586 ! a Trace/BPT fault on the IBM (crashed the debugger too!).
587 !
588 ! Revision 2.0 2004/08/12 22:23:16 paulv
589 ! - New version.
590 ! - Swap_Endian functions are now ELEMENTAL and accept any rank array input.
591 !
592 ! Revision 1.3 2004/07/01 17:44:25 paulv
593 ! - Repository resync. Last modified Nov 8, 2001.
594 !
595 ! Revision 1.2 2000/06/02 16:26:12 paulv
596 ! Removed 8-byte integer swapping routines. This data type is not generally
597 ! supported so the functionality was removed.
598 !
599 ! Revision 1.1 2000/04/03 14:48:43 paulv
600 ! Initial checked in version
601 !
602 !
integer, parameter, public n_bytes_single
Definition: Type_Kinds.f90:110
logical function, public big_endian()
integer, parameter, public n_bytes_long
Definition: Type_Kinds.f90:82
integer, parameter, public double
Definition: Type_Kinds.f90:106
integer, parameter, public single
Definition: Type_Kinds.f90:105
elemental real(double) function swap_double_float(Input)
integer, parameter, public n_bytes_double
Definition: Type_Kinds.f90:111
integer, parameter, public n_bytes_llong
Definition: Type_Kinds.f90:83
elemental integer(short) function swap_short_integer(Input)
elemental integer(long) function swap_long_integer(Input)
elemental integer(llong) function swap_llong_integer(Input)
integer, parameter, public n_bytes_short
Definition: Type_Kinds.f90:81
elemental complex(double) function swap_double_complex(Input)
elemental complex(single) function swap_single_complex(Input)
elemental real(single) function swap_single_float(Input)