Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Adapt to lastest changes in dict: Create dicts before use
[simgrid.git] / src / nws_portability / formatutil.c
1 /* $Id$ */
2
3
4 #include <string.h>  /* memcpy() */
5 #include "diagnostic.h"
6 #include "formatutil.h"
7 #include "osutil.h"
8
9
10 #ifndef NORMAL_FP_FORMAT
11 #define INCLUDE_FORMAT_CHECKING
12 #else
13 #ifndef NORMAL_INT_FORMAT
14 #define INCLUDE_FORMAT_CHECKING
15 #endif
16 #endif
17
18
19 static void *lock = NULL;                       /* local mutex */
20 static const size_t HOST_SIZE[SIMPLE_TYPE_COUNT] =
21         {sizeof(char), sizeof(double), sizeof(float), sizeof(int), sizeof(long),
22         sizeof(short), sizeof(unsigned int), sizeof(unsigned long),
23         sizeof(unsigned short)};
24 static const size_t NETWORK_SIZE[SIMPLE_TYPE_COUNT] =
25         {1, 8, 4, 4, 4, 2, 4, 4, 2};
26
27 /* how this host treat int, floats and big/little endianness */
28 static int unusualFPFormat = 0;
29 static int unusualIntFormat = 0;
30 static int bytesReversed = -1;
31
32 #ifndef NORMAL_FP_FORMAT
33 /*
34 ** Copies #source# to #destination#, converting between IEEE and host floating-
35 ** point format.  #whatType# must be DOUBLETYPE or FLOATTYPE.  #hostToIEEE#
36 ** indicates whether the conversion is from host format to IEEE or vice versa.
37 ** The IEEE version of the data will be in big-endian byte order even if the
38 ** host machine is little-endian.  For IEEE 754 floating point info, look at
39 ** http://www.research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
40 */
41 /* It should be thread safe */
42 void
43 ConvertIEEE(    const void *destination,
44                 const void *source,
45                 DataTypes whatType,
46                 int hostToIEEE) {
47
48 #define DOUBLEBIAS 1023
49 #define QUADBIAS 16383
50 #define SINGLEBIAS 127
51
52         struct DoublePrecision {
53                 unsigned sign : 1;
54                 unsigned exponent : 11;
55                 unsigned leading : 4;
56                 unsigned char mantissa[6];
57         } doublePrecision;
58
59         struct Expanded {
60                 unsigned char sign;
61                 int exponent;
62                 unsigned char mantissa[16];
63         } expanded;
64
65         struct QuadPrecision {
66                 unsigned sign : 1;
67                 unsigned exponent : 15;
68                 unsigned char mantissa[14];
69         }; /* For future reference. */
70
71         struct SinglePrecision {
72                 unsigned sign : 1;
73                 unsigned exponent : 8;
74                 unsigned leading : 7;
75                 unsigned char mantissa[2];
76         } singlePrecision;
77
78         double doubleValue;
79         unsigned exponentBias;
80         double factor;
81         int i;
82         size_t mantissaLength;
83
84         if(whatType == DOUBLE_TYPE) {
85                 exponentBias = DOUBLEBIAS;
86                 mantissaLength = sizeof(doublePrecision.mantissa) + 1;
87                 factor = 16.0; /* 2.0 ^ bitsize(doublePrecision.leading) */
88         } else {
89                 exponentBias = SINGLEBIAS;
90                 mantissaLength = sizeof(singlePrecision.mantissa) + 1;
91                 factor = 128.0; /* 2.0 ^ bitsize(singlePrecision.leading) */
92         }
93
94         if(hostToIEEE) {
95                 if(whatType == DOUBLE_TYPE)
96                         doubleValue = *(double *)source;
97                 else
98                         doubleValue = *(float *)source;
99
100                 if(doubleValue < 0.0) {
101                         expanded.sign = 1;
102                         doubleValue = -doubleValue;
103                 } else {
104                         expanded.sign = 0;
105                 }
106                 expanded.exponent = 0;
107                 if(doubleValue != 0.0) {
108                 /* Determine the exponent value by iterative shifts
109                  * (mult/div by 2) */
110                         while(doubleValue >= 2.0) {
111                                 expanded.exponent += 1;
112                                 doubleValue /= 2.0;
113                         }
114                         while(doubleValue < 1.0) {
115                                 expanded.exponent -= 1;
116                                 doubleValue *= 2.0;
117                         }
118                         expanded.exponent += exponentBias;
119                         doubleValue -= 1.0;
120                 }
121
122                 /* Set the bytes of the mantissa by iterative shift and
123                  * truncate. */
124                 for(i = 0; i < 16; i++) {
125                         doubleValue *= factor;
126                         expanded.mantissa[i] = (int)doubleValue;
127                         doubleValue -= expanded.mantissa[i];
128                         factor = 256.0;
129                 }
130                 /* Pack the expanded version into the destination. */
131                 if(whatType == DOUBLE_TYPE) {
132                         memcpy(doublePrecision.mantissa, &expanded.mantissa[1], sizeof(doublePrecision.mantissa));
133                         doublePrecision.leading = expanded.mantissa[0];
134                         doublePrecision.exponent = expanded.exponent;
135                         doublePrecision.sign = expanded.sign;
136                         *(struct DoublePrecision *)destination = doublePrecision;
137                 } else {
138                         memcpy(singlePrecision.mantissa, &expanded.mantissa[1], sizeof(singlePrecision.mantissa));
139                         singlePrecision.leading = expanded.mantissa[0];
140                         singlePrecision.exponent = expanded.exponent;
141                         singlePrecision.sign = expanded.sign;
142                         *(struct SinglePrecision *)destination = singlePrecision;
143                 }
144         } else {
145                 /* Unpack the source into the expanded version. */
146                 if(whatType == DOUBLE_TYPE) {
147                         doublePrecision = *(struct DoublePrecision *)source;
148                         expanded.sign = doublePrecision.sign;
149                         expanded.exponent = doublePrecision.exponent;
150                         expanded.mantissa[0] = doublePrecision.leading;
151                         memcpy(&expanded.mantissa[1], doublePrecision.mantissa, sizeof(doublePrecision.mantissa));
152                 } else {
153                         singlePrecision = *(struct SinglePrecision *)source;
154                         expanded.sign = singlePrecision.sign;
155                         expanded.exponent = singlePrecision.exponent;
156                         expanded.mantissa[0] = singlePrecision.leading;
157                         memcpy(&expanded.mantissa[1], singlePrecision.mantissa, sizeof(singlePrecision.mantissa));
158                 }
159                 /* Set mantissa by via shifts and adds; allow for
160                  * denormalized values. */
161                 doubleValue = (expanded.exponent == 0) ? 0.0 : 1.0;
162
163                 for(i = 0; i < mantissaLength; i++) {
164                         doubleValue += (double)expanded.mantissa[i] / factor;
165                         factor *= 256.0;
166                 }
167                 /* Set the exponent by iterative mults/divs by 2. */
168                 if(expanded.exponent == 0)
169                         ; /* Nothing to do. */
170                 else if(expanded.exponent == (exponentBias * 2 + 1))
171                         /*
172                          * An exponent of all ones represents one of
173                          * three things: Infinity: mantissa of all zeros
174                          * Indeterminate: sign of 1, mantissa leading one
175                          * followed by all zeros NaN: all other values
176                          * None of these can be reliably produced by C
177                          * operations.  We might be able to get Infinity
178                          * by dividing by zero, but, on a non-IEEE
179                          * machine, we're more likely to cause some sort
180                          * of floating-point exception.
181                          */
182                         ;
183                 else
184                         expanded.exponent -= exponentBias;
185
186                 if(expanded.exponent < 0) {
187                         for(i = expanded.exponent; i < 0; i++)
188                                 doubleValue /= 2.0;
189                 } else {
190                         for(i = 0; i < expanded.exponent; i++)
191                         doubleValue *= 2.0;
192                 }
193
194                 if(expanded.sign)
195                         doubleValue *= -1.0;
196
197                 if(whatType == DOUBLE_TYPE)
198                         *(double *)destination = doubleValue;
199                 else
200                         *(float *)destination = doubleValue;
201         }
202 }
203 #endif
204
205
206 /*
207  * Copies the integer value of size #sourceSize# stored in #source# to the
208  * #destinationSize#-long area #destination#.  #signedType# indicates whether
209  * or not the source integer is signed; #lowOrderFirst# whether or not the
210  * bytes run least-significant to most-significant.
211  *
212  * It should be thread safe (operates on local variables and calls mem*)
213  */
214 void
215 ResizeInt(      void *destination,
216                 size_t destinationSize,
217                 const void *source,
218                 size_t sourceSize,
219                 int signedType,
220                 int lowOrderFirst) {
221
222         unsigned char *destinationSign;
223         int padding;
224         int sizeChange = destinationSize - sourceSize;
225         unsigned char *sourceSign;
226
227         if(sizeChange == 0) {
228                 memcpy(destination, source, destinationSize);
229         } else if(sizeChange < 0) {
230                 /* Truncate high-order bytes. */
231                 memcpy(destination, lowOrderFirst?source:((char*)source-sizeChange), destinationSize);
232                 if(signedType) {
233                         /* Make sure the high order bit of source and
234                          * destination are the same */
235                         destinationSign = lowOrderFirst ? ((unsigned char*)destination + destinationSize - 1) : (unsigned char*)destination;
236                         sourceSign = lowOrderFirst ? ((unsigned char*)source + sourceSize - 1) : (unsigned char*)source;
237                         if((*sourceSign > 127) != (*destinationSign > 127)) {
238                                 if(*sourceSign > 127)
239                                         *destinationSign += 128;
240                                 else
241                                         *destinationSign -= 128;
242                         }
243                 }
244         } else {
245                 /* Pad with zeros or extend sign, as appropriate. */
246                 if(!signedType)
247                         padding = 0;
248                 else {
249                         sourceSign = lowOrderFirst ? ((unsigned char*)source + sourceSize - 1) : (unsigned char*)source;
250                         padding = (*sourceSign > 127) ? 0xff : 0;
251                 }
252                 memset(destination, padding, destinationSize);
253                 memcpy(lowOrderFirst ? destination : ((char *)destination + sizeChange), source, sourceSize);
254         }
255 }
256
257
258 /*
259  * Copies #length# bytes from #from# to #to# in reverse order.  Will work
260  * properly if #from# and #to# are the same address.
261  *
262  * It should be thread safe.
263  */
264 void
265 ReverseBytes(   void *to,
266                 const void *from,
267                 size_t length) {
268
269         char charBegin;
270         const char *fromBegin;
271         const char *fromEnd;
272         char *toBegin;
273         char *toEnd;
274
275         for(fromBegin = (const char *)from, fromEnd = fromBegin + length - 1, toBegin = (char *)to, toEnd = toBegin + length - 1; fromBegin <= fromEnd; fromBegin++, fromEnd--, toBegin++, toEnd--) {
276                 charBegin = *fromBegin;
277                 *toBegin = *fromEnd;
278                 *toEnd = charBegin;
279         }
280 }
281
282
283 void
284 ConvertData(    void *destination,
285                 const void *source,
286                 const DataDescriptor *description,
287                 size_t length,
288                 FormatTypes sourceFormat) {
289
290         size_t destStructSize;
291         int i;
292         int j;
293         size_t networkBytesConverted;
294         char *nextDest;
295         const char *nextSource;
296         size_t sourceStructSize;
297
298         networkBytesConverted = 0;
299
300         for(i = 0; i < length; i++, description++) {
301                 if(sourceFormat == HOST_FORMAT) {
302                         nextDest = (char *)destination + networkBytesConverted;
303                         nextSource = (char *)source + description->offset;
304                 } else {
305                         nextDest = (char *)destination + description->offset;
306                         nextSource = (char *)source + networkBytesConverted;
307                 }
308                 if(description->type == STRUCT_TYPE) {
309                         if(sourceFormat == HOST_FORMAT) {
310                                 destStructSize = DataSize(description->members, description->length, NETWORK_FORMAT);
311                                 sourceStructSize = DataSize(description->members, description->length, HOST_FORMAT) + description->tailPadding;
312                         } else {
313                                 destStructSize = DataSize(description->members, description->length, HOST_FORMAT) + description->tailPadding;
314                                 sourceStructSize = DataSize(description->members, description->length, NETWORK_FORMAT);
315                         }
316                         for(j = 0; j < description->repetitions; j++) {
317                                 ConvertData(nextDest, nextSource, description->members, description->length, sourceFormat);
318                                 nextDest += destStructSize;
319                                 nextSource += sourceStructSize;
320                         }
321                 } else {
322                         HomogenousConvertData(nextDest, nextSource, description->type, description->repetitions, sourceFormat);
323                 }
324                 networkBytesConverted += DataSize(description, 1, NETWORK_FORMAT);
325         }
326 }
327
328
329 /* I believe is thread safe (HomogenousDataSize is thread safe) */
330 size_t
331 DataSize(       const DataDescriptor *description,
332                 size_t length,
333                 FormatTypes format) {
334
335         int i;
336         const DataDescriptor *lastMember;
337         size_t totalSize;
338
339         if(format == HOST_FORMAT) {
340                 lastMember = description;
341                 for(i = 0; i < length; i++) {
342                         if(description[i].offset > lastMember->offset) {
343                                 lastMember = &description[i];
344                         }
345                 }
346                 return lastMember->offset + ((lastMember->type == STRUCT_TYPE) ?  ((DataSize(lastMember->members, lastMember->length, HOST_FORMAT) + lastMember->tailPadding) * lastMember->repetitions) : HomogenousDataSize(lastMember->type, lastMember->repetitions, HOST_FORMAT));
347         } else {
348                 totalSize = 0;
349                 for(i = 0; i < length; i++, description++) {
350                         totalSize += (description->type == STRUCT_TYPE) ?  (DataSize(description->members, description->length, NETWORK_FORMAT) * description->repetitions) : HomogenousDataSize(description->type, description->repetitions, NETWORK_FORMAT);
351                 }
352                 return totalSize;
353         }
354 }
355
356
357 /*
358  * Internal call to be done only once. We find the fomrat of this host:
359  * once done we re-use the results
360  * 
361  * Some of the checking could have been done at compile time, but to be
362  * sure and to cover exoteric machine (doesn't ppc can behave as little
363  * and bin endian?) we do it at runtime.
364  *
365  * I believe it is thread safe (uses the lock if it modifies global
366  * variables)
367  */
368 void
369 FirstCall() {
370
371         /* we do the checking only once: next time bytesReversed will be
372          * set */
373         if (bytesReversed == -1) {
374                 /* I think we could avoid this lock, but just to be safe */
375                 GetNWSLock(&lock);
376
377                 /* check endiannes */
378                 {
379                 typedef int IntTestType;
380                 union {
381                         IntTestType testInt;
382                         unsigned char bytes[sizeof(IntTestType)];
383                 } orderTester;
384
385                 orderTester.testInt = 1;
386                 bytesReversed = (orderTester.bytes[0] == 1);
387                 }
388
389 #ifdef INCLUDE_FORMAT_CHECKING
390 #       ifndef NORMAL_FP_FORMAT
391                 {
392                 typedef double FPTestType;
393                 union {
394                         FPTestType testFP;
395                         unsigned char bytes[sizeof(FPTestType)];
396                 } fpTester;
397                 
398                 memset(&fpTester, 0, sizeof(fpTester));
399                 /* Set sign, low-order bit of exponent and high-order bit 
400                  * of mantissa. */
401                 fpTester.bytes[bytesReversed ? sizeof(FPTestType) - 1 : 0]=192;
402                 fpTester.bytes[bytesReversed ? sizeof(FPTestType) - 2 : 1] =
403                 (sizeof(FPTestType) == 4)  ? 128 :
404                 (sizeof(FPTestType) == 8)  ? 16 :
405                 (sizeof(FPTestType) == 16) ? 1 : 0;
406                 unusualFPFormat = fpTester.testFP != -4.0;
407                 }
408 #       endif
409
410 #       ifndef NORMAL_INT_FORMAT
411                 /* Converting non-twos-compliment is a pain, but
412                  * detecting it is easy, so we go ahead and include a
413                  * check and leave it to the caller to handle.  */
414                 {
415                 typedef int IntTestType;
416                 union {
417                         IntTestType testInt;
418                         unsigned char bytes[sizeof(IntTestType)];
419                 } intTester;
420
421                 intTester.testInt = -2;
422                 unusualIntFormat = ((unsigned int)intTester.bytes[0] +
423                         (unsigned int)intTester.bytes[sizeof(IntTestType) - 1]) != 509;
424                 }
425 #       endif
426 #endif
427
428                 ReleaseNWSLock(&lock);
429         }
430         return;
431 }
432
433 /* I believe is thread safe (FirstCall is thread safe and we just read
434  * the global variables) */
435 int
436 DifferentFormat(DataTypes whatType) {
437
438         FirstCall();
439         return ((whatType == DOUBLE_TYPE) || (whatType == FLOAT_TYPE)) ?
440                         unusualFPFormat : unusualIntFormat;
441 }
442
443
444 /* I believe is thread safe (FirstCall is thread safe and we just read
445  * the global variable) */
446 int
447 DifferentOrder(void) {
448
449         FirstCall();
450         return bytesReversed;
451 }
452
453
454 /* It should be thread sage (only reads global variables) */
455 int
456 DifferentSize(DataTypes whatType) {
457         return HOST_SIZE[whatType] != NETWORK_SIZE[whatType];
458 }
459
460
461 /* It should be thread safe (ConvertIEEE, ReverseData
462  * and mem* are thread safe) */
463 void
464 HomogenousConvertData(  void *destination,
465                         const void *source,
466                         DataTypes whatType,
467                         size_t repetitions,
468                         FormatTypes sourceFormat) {
469
470         int bytesReverse = DifferentOrder();
471         FormatTypes destFormat;
472         const void *from;
473         size_t fromSize;
474         int i;
475         void *to;
476         size_t toSize;
477
478         destFormat = (sourceFormat == HOST_FORMAT) ? NETWORK_FORMAT : HOST_FORMAT;
479         fromSize = (sourceFormat == HOST_FORMAT) ?
480                 HOST_SIZE[whatType] : NETWORK_SIZE[whatType];
481         toSize = (destFormat == HOST_FORMAT) ?
482                 HOST_SIZE[whatType] : NETWORK_SIZE[whatType];
483
484 #ifndef NORMAL_FP_FORMAT
485         if(((whatType == DOUBLE_TYPE) || (whatType == FLOAT_TYPE)) &&
486                         (DifferentFormat(whatType) || (fromSize != toSize))) {
487                 for(i = 0, from = source, to = destination; i < repetitions; i++, from = (char *)from + fromSize, to = (char *)to + toSize) {
488                         ConvertIEEE(to, from, whatType, (sourceFormat == HOST_FORMAT));
489                 }
490                 /* Note: ConvertIEEE also handles byte ordering. */
491                 return;
492         }
493 #endif
494
495         if(fromSize != toSize) {
496                 for(i = 0, from = source, to = destination; i < repetitions; i++, from = (char *)from + fromSize, to = (char *)to + toSize) {
497                         ResizeInt(to, toSize, from, fromSize, whatType < UNSIGNED_INT_TYPE, (sourceFormat == HOST_FORMAT) && bytesReverse);
498                 }
499                 if(bytesReverse && (toSize > 1))
500                         ReverseData(destination, destination, whatType, repetitions, destFormat);
501         } else if(bytesReverse && (toSize > 1))
502                 ReverseData(destination, source, whatType, repetitions, destFormat);
503         else if(destination != source)
504                 memcpy(destination, source, fromSize * repetitions);
505 }
506
507
508 /* I believe is thread safe (*_SIZE are static and global but are
509  * constant and initialize when created) */
510 size_t
511 HomogenousDataSize(     DataTypes whatType,
512                         size_t repetitions,
513                         FormatTypes format) {
514         return ((format == HOST_FORMAT) ?
515                 HOST_SIZE[whatType] : NETWORK_SIZE[whatType]) * repetitions;
516 }
517
518
519 /* It should be thread safe (ReverseByte is thread safe */
520 void
521 ReverseData(    void *destination,
522                 const void *source,
523                 DataTypes whatType,
524                 int repetitions,
525                 FormatTypes format) {
526         int i;
527         size_t size;
528
529         size = (format == HOST_FORMAT) ? HOST_SIZE[whatType] : NETWORK_SIZE[whatType];
530         for(i = 0; i < repetitions; i++, destination = (char *)destination + size, source = (char *)source + size) {
531                 ReverseBytes(destination, source, size);
532         }
533 }