libMVRgdtf 40bc00a
A library for GDTF and MVR
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GSUtil.h
Go to the documentation of this file.
1//
2// Copyright Nemetschek Vectorworks, Inc.
3// Use of this file is governed by the Nemetschek Vectorworks SDK License Agreement
4// http://developer.vectorworks.net/index.php?title=Vectorworks_SDK_License
5//
6// This file contains utility functions for the GraphSoft Core.
7//
8
9#ifndef _GS_UTIL_
10#define _GS_UTIL_
11
12#pragma once
13
14#include "GSTypes.h"
15
16#if _WINDOWS
17 #if _MINICAD_EXTERNAL_ || _GSWINSDK_
18 #if GS_INTERFACE_FACTORING
19
20 #include "QTHeader.h"
21
22 #else
23 #include "MCTypes.h"
24 #endif
25 #endif
26#else
27 #if TARGET_RT_MAC_CFM
28 #include <MacTypes.h>
29 #endif
30#endif
31
32
33#if __cplusplus
34
35#if _WINDOWS
36 // We are going to define min() and max() as templates; however, at this
37 // point, they have already been defined as macros by "windef.h", so we
38 // undefined them here. [DMB, 10/19/95]
39 #if defined(min)
40 #undef min
41 #endif
42 #if defined(max)
43 #undef max
44 #endif
45#endif // _WINDOWS
46
47#include <algorithm>
48
50// Macros for unused parameters. Use these instead of just commenting
51// out the parameter name.
52
53#ifdef __AFX_H__
54 // MFC defines its own UNUSED macro that does not appear to have the same
55 // meaning and use as our own. [DMB 7/27/99]
56#else
57 #define UNUSED(x)
58#endif
59
60#if GS_CLASSIC_SHELL
61 #define CLASSIC_ONLY(x) x
62#else
63 #define CLASSIC_ONLY(x)
64#endif
65
66#if _WINDOWS
67 #define MAC_ONLY(x)
68 #define WIN_ONLY(x) x
69 #define MAC_WIN(m, w) w
70 #ifndef GS_LITTLE_ENDIAN
71 #define GS_LITTLE_ENDIAN 1
72 #endif
73 #ifndef GS_BIG_ENDIAN
74 #define GS_BIG_ENDIAN 0
75 #endif
76#else
77 #define MAC_ONLY(x) x
78 #define WIN_ONLY(x)
79 #define MAC_WIN(m, w) m
80#endif
81
82
83
84inline Bool8 podd(SintptrT x) { return (x & 1) != 0; }
85
87// Supplementary min and max functions to provide matches for min(x, <constant>).
88//
89inline int16_t min(int16_t a, int16_t b) { return a > b ? b : a; }
90inline int32_t min(int32_t a, int32_t b) { return a > b ? b : a; }
91inline int64_t min(int64_t a, int64_t b) { return a > b ? b : a; }
92inline size_t min(size_t a, size_t b) { return a > b ? b : a; }
93#if GS_MAC
94inline uint32_t min(uint32_t a, uint32_t b) { return a > b ? b : a; } //X64PRJ_REVISIT Miriam - Mac seemed to need this; but in Win it produced size_t conflict
95#endif
96inline float min(float a, float b) { return a > b ? b : a; }
97inline double min(double a, double b) { return a > b ? b : a; }
98//inline float min(double a, float b) { return (float)a > b ? b : (float)a; }
99//inline float min(float a, double b) { return a > (float)b ? (float)b : a; }
100//inline float min(float a, float b) { return a > b ? b : a; }
101
102inline int16_t max(int16_t a, int16_t b) { return b > a ? b : a; }
103inline int32_t max(int32_t a, int32_t b) { return b > a ? b : a; }
104inline int64_t max(int64_t a, int64_t b) { return b > a ? b : a; }
105inline size_t max(size_t a, size_t b) { return b > a ? b : a; }
106inline float max(float a, float b) { return b > a ? b : a; }
107inline double max(double a, double b) { return b > a ? b : a; }
108//inline float max(double a, float b) { return (float)a > b ? b : (float)a; }
109//inline float max(float a, double b) { return a > (float)b ? (float)b : a; }
110//inline float max(float a, float b) { return a > b ? b : a; }
111
112inline int32_t min(int16_t a, int32_t b) { return min((int32_t) a, b); }
113inline int32_t min(int32_t a, int16_t b) { return min(a, (int32_t) b); }
114inline int64_t min(int64_t a, int32_t b) { return min(a, (int64_t) b); }
115inline int64_t min(int32_t a, int64_t b) { return min((int64_t) a, b); }
116
117inline int32_t max(int16_t a, int32_t b) { return max((int32_t) a, b); }
118inline int32_t max(int32_t a, int16_t b) { return max(a, (int32_t) b); }
119inline int64_t max(int64_t a, int32_t b) { return max(a, (int64_t) b); }
120inline int64_t max(int32_t a, int64_t b) { return max((int64_t) a, b); }
121
123// PIN template function (constrains input v to be in the interval [lo, hi].)
124//
125
126template <class T1, class T2, class T3>
127inline T1 PIN(const T1& v, const T2& lo, const T3& hi)
128 { return (v < (T1)lo) ? (T1)lo : (v >(T1) hi) ? (T1)hi : v; }
129
130
131/*
132template <class T>
133inline const T& PIN(const T& v, const T& lo, const T& hi)
134 { return (v < lo) ? lo : (v > hi) ? hi : v; }
135
136template <class IntegralType>
137inline IntegralType PIN(IntegralType v, Sint32 lo, Sint32 hi)
138 { return (v < (IntegralType)lo) ? (IntegralType) lo : (v > (IntegralType)hi) ? (IntegralType) hi : v; }
139
140inline Sint32 PIN(Sint32 v, Sint32 lo, Sint32 hi)
141 { return (v < lo) ? lo : (v > hi) ? hi : v; }
142*/
143
144inline Sint32 PIN(Sint32 v, Sint32 lo, Sint32 hi, Bool8& outWasPinned)
145{
146 Sint32 result = (v < lo) ? lo : (v > hi) ? hi : v;
147 outWasPinned = (v == result) ? false : true;
148 return result;
149}
150
152// Casting macros (can be used as l-values.)
153// Do not use these unless you need them. Do not use them for convenience.
154// If you think you need to cast, try const_cast, static_cast, or static_cast.
155
156#define CAST(Type, thing) (*((Type *) &(thing)))
157#define CAST_SHORT(x) (*((short *) &(x)))
158#define CAST_LONG(x) (*((Sint32 *) &(x)))
159
160
162
163union HiLo {
164#if GS_LITTLE_ENDIAN
165 struct { short lo, hi; } shortWord;
166 Sint32 longWord;
167#else
168 struct { short hi, lo; } shortWord;
169 Sint32 longWord;
170#endif
171}; // Used for extracting short words from Sint32 words. THIS IS MACHINE DEPENDENT.
172
173inline const short HiWrd(const Sint32& x) { return ((const HiLo *) &x)->shortWord.hi; }
174inline const short LoWrd(const Sint32& x) { return ((const HiLo *) &x)->shortWord.lo; }
175inline short& HiWrd(Sint32& x) { return ((HiLo *) &x)->shortWord.hi; }
176inline short& LoWrd(Sint32& x) { return ((HiLo *) &x)->shortWord.lo; }
177// XXX_JDW_MISC - maybe make a << and >> version called HighWord and LowWord that might be faster for some purposes
178
179// See also PinToCoord in MCCoordTypes.h
180
182template<class A, class B, class C>
183inline bool inrange(A value, B lowerBound, C upperBound)
184 { return (value >= lowerBound && value <= upperBound); }
185
186inline void ClipTop(short &x, short upperBound) { if (x > upperBound) x = upperBound; }
187inline void ClipTop(Sint32 &x, Sint32 upperBound) { if (x > upperBound) x = upperBound; }
188inline void ClipBottom(short &x, short lowerBound) { if (x < lowerBound) x = lowerBound; }
189inline void ClipBottom(Sint32 &x, Sint32 lowerBound) { if (x < lowerBound) x = lowerBound; }
190
191inline void ClipNum(short &x, short lowerBound, short upperBound)
192 { if (x < lowerBound) x = lowerBound; else if (x > upperBound) x = upperBound; }
193
194inline void ClipNum(Sint32 &x, Sint32 lowerBound, Sint32 upperBound)
195 { if (x < lowerBound) x = lowerBound; else if (x > upperBound) x = upperBound; }
196
197inline void ClipNum(double &x, double lowerBound, double upperBound)
198 { if (x < lowerBound) x = lowerBound; else if (x > upperBound) x = upperBound; }
199
201
202// Translate the bit position of a bit in a Motorola Sint32 to its position in
203// a native Sint32. [DMB, 6/15/95]
204inline void TranslateBitPosition32(Sint32 *pBit)
205{
206 #if GS_LITTLE_ENDIAN
207 // Translate the bit position of a bit in a big endian Sint32 to its
208 // position in an little endian Sint32.
209 if (*pBit < 8) *pBit += 24;
210 else if (*pBit < 16) *pBit += 8;
211 else if (*pBit < 24) *pBit -= 8;
212 else *pBit -= 24;
213 #else
214 // Translate the bit position of a bit in a Motorola Sint32 to its
215 // position in a Motorola Sint32.
216 // #pragma unused(pBit)
217 #endif
218}
219//
220// Work on Motorola byte order.
221inline void pbitclear(Sint32 &x, Sint32 bit) { x &= ~(1L << (bit&31)); }
222inline Bool8 pbittest(Sint32 x, Sint32 bit) { return (x & (1L << (bit&31))) != 0; }
223inline void pbitset(Sint32 &x, Sint32 bit) { x |= (1L << (bit&31)); }
224//
225// Work on native byte order.
226inline void _pbitclear(Sint32 &x, Sint32 bit) { TranslateBitPosition32(&bit); pbitclear(x,bit); }
227inline Bool8 _pbittest(Sint32 x, Sint32 bit) { TranslateBitPosition32(&bit); return pbittest(x,bit); }
228inline void _pbitset(Sint32 &x, Sint32 bit) { TranslateBitPosition32(&bit); pbitset(x,bit); }
229
230
231/* for portability, different ways of expressing a char w/ all 1's */
232#if _WINDOWS
233 #define CHAR0xFF ('\xFF')
234#else
235 #define CHAR0xFF (0xFF)
236#endif
237
238
240// --- Sets
241
242typedef Uint32 Set32;
243typedef unsigned short Set16;
244typedef unsigned char Set8;
245
246Bool8 _setmember(Sint32 c, ...);
247
248
249// 4/25/00 - JDW
250template<class X, class T> inline bool setmember(X x, T a, T b)
251 { return (x == a || x == b); }
252template<class X, class T> inline bool setmember(X x, T a, T b, T c)
253 { return (x == a || x == b || x == c); }
254template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d)
255 { return (x == a || x == b || x == c || x == d); }
256template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e)
257 { return (x == a || x == b || x == c || x == d || x == e); }
258template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f)
259 { return (x == a || x == b || x == c || x == d || x == e || x == f); }
260template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g)
261 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g); }
262template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h)
263 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h); }
264template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i)
265 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i); }
266template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i, T j)
267 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i || x == j); }
268template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k)
269 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i || x == j || x == k); }
270template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l)
271 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i || x == j || x == k || x == l); }
272template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l, T m)
273 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i || x == j || x == k || x == l || x == m); }
274template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l, T m, T n)
275 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i || x == j || x == k || x == l || x == m || x == n); }
276template<class X, class T> inline bool setmember(X x, T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l, T m, T n, T o)
277 { return (x == a || x == b || x == c || x == d || x == e || x == f || x == g || x == h || x == i || x == j || x == k || x == l || x == m || x == n || x == o); }
278
279
280/* Set of 0..2047 */
281class IntegerSet {
282 private:
283 enum { numLongs = 64 } ;
284 enum { maxElement = numLongs * 32 - 1 } ;
285 Sint32 bits[numLongs];
286 public:
287 IntegerSet();
288 IntegerSet(short i0, short i1 = -1, short i2 = -1, short i3 = -1,
289 short i4 = -1, short i5 = -1, short i6 = -1, short i7 = -1,
290 short i8 = -1, short i9 = -1);
291 IntegerSet(const IntegerSet &s);
292
293 Bool8 contains(short i) const;
294 void operator +=(short i);
295 void operator +=(const IntegerSet &s);
296 void operator -=(short i);
297 void operator -=(const IntegerSet &s);
298 IntegerSet& operator =(const IntegerSet &s);
299};
300
301Boolean OSIsMetric();
302
304// TernaryXOR -
305// Returns true iff only one of the three values is true, otherwise false
307
308inline bool TernaryXOR(bool a, bool b, bool c)
309{
310 return (!a && (b ^ c)) || (a && !(b || c));
311}
312
314// Cross-Platform byte swapping functions
316
317
318// for ByteSwap conversion direction parameter
319enum EByteSwapDirection {
320 kReading,
321 kWriting
322};
323
324
325
326
327inline void ByteSwapDouble(double *pld)
328{
329 char t;
330 char *pb1 = (char *) pld;
331 char *pb2 = pb1 + sizeof(Real64) - 1;
332 while (pb2 > pb1) {
333 t = *pb1;
334 *pb1 = *pb2;
335 *pb2 = t;
336 ++pb1;
337 --pb2;
338 }
339}
340
341
342
343inline void ByteSwapFloat(float *pf)
344{
345 char t;
346 char *pb1 = (char *) pf;
347 char *pb2 = pb1 + sizeof(float) - 1;
348 while (pb2 > pb1) {
349 t = *pb1;
350 *pb1 = *pb2;
351 *pb2 = t;
352 ++pb1;
353 --pb2;
354 }
355}
356
357inline void ByteSwapUint64(Uint64 *pld)
358{
359 char t;
360 char *pb1 = (char *) pld;
361 char *pb2 = pb1 + sizeof(Uint64) - 1;
362 while (pb2 > pb1) {
363 t = *pb1;
364 *pb1 = *pb2;
365 *pb2 = t;
366 ++pb1;
367 --pb2;
368 }
369}
370
371inline void ByteSwapUint32(Uint32 *pld)
372{
373 char t;
374 char *pb1 = (char *) pld;
375 char *pb2 = pb1 + sizeof(Uint32) - 1;
376 while (pb2 > pb1) {
377 t = *pb1;
378 *pb1 = *pb2;
379 *pb2 = t;
380 ++pb1;
381 --pb2;
382 }
383}
384
385inline void ByteSwapLONG(Sint32 *pl)
386{
387 char t;
388 char* p1 = (char*)pl;
389 char* p2 = p1 + 3;
390
391 t = *p1;
392 *p1 = *p2;
393 *p2 = t;
394
395 ++p1; --p2;
396
397 t = *p1;
398 *p1 = *p2;
399 *p2 = t;
400}
401
402#if GS_MAC && GS_PLATFORM32
403//X64PRJ_REVISIT Hugues // QTREMOVAL
404inline void ByteSwapLONG(long *pl)
405{
406 ByteSwapLONG((Sint32 *)pl);
407}
408#endif
409
410
411inline void ByteSwapSHORT(Sint16 *ps)
412{
413 char *p1 = (char*)ps;
414 char *p2 = p1 + 1;
415 char t = *p1;
416 *p1 = *p2;
417 *p2 = t;
418}
419
420inline void ByteSwapDWORD(Uint32 *pl)
421{
422 ByteSwapLONG((Sint32 *)pl);
423}
424
425#if GS_MAC && GS_PLATFORM32
426//X64PRJ_REVISIT Hugues // QTREMOVAL
427inline void ByteSwapDWORD(unsigned long *pl)
428{
429 ByteSwapLONG((Sint32 *)pl);
430}
431#endif
432
433inline void ByteSwapWORD(Uint16 *ps)
434{
435 ByteSwapSHORT((Sint16 *)ps);
436}
437
438inline Uint32 TruncatePointer(const void* ptr)
439{
440 return (Uint32)((UintptrT)ptr); //-V202
441}
442
443
445// Casting related functions.
446
447// Intended use of DemoteTo, Trunctate, Round and PinTo.
448//
449// The DemoteTo casting function is intended to be used in any case where a cast is performed between numerical types in such a way
450// that data can be lost depending on the value of the variable being cast. The .NET compiler on Windows will generate a warning or error
451// in these cases if the cast is not explicit.
452//
453// Rather than using an explicit cast to satisfy these cases, VectorWorks code is required to use the DemoteTo function as follows:
454//
455// shortVariable = (short)longVariable; //NOT PREFERRED
456//
457// shortVariable = DemoteTo<short>(kVictor, longVariable); //PREFERRED
458//
459// This allows the DemoteTo function to perform rigorous runtime checks to prevent unexpected data values from going unnoticed
460// and causing subtle or serious functional problems.
461//
462// Cases where DemoteTo must be used:
463//
464// floating point to integer
465// (double to Sint32)
466// signed integer to unsigned integer of any size
467// (char to Uint32)
468// unsigned integer to signed integer of the same or smaller size
469// (unsigned short to short)
470// larger integer to smaller integer
471// (Sint32 to short or short to char)
472// larger floating point to smaller floating point
473// (double to float)
474// Sint32 integer to short floating point
475// (Sint32 to float)
476//
477// Cases where a DemoteTo should not be used:
478//
479// integer to floating point
480// (Sint32 to double)
481// integer to boolean
482// (Sint32 to bool)
483// smaller integer to larger integer
484// (short to Sint32)
485// assignments between like types
486// (Sint32 to Sint32)
487// shorter floating point to longer floating point
488// (float to double)
489// non-numeric types
490// (handles, classes, strings, etc.)
491//
492// An important side effect of this requirement is that you understand that casting alone can no longer be used to intentionally
493// truncate floating point values or pin or wrap integer values. The value passed into the DemoteTo function must be exactly
494// representable by the destination variable or a runtime ASSERT message will be generated, which is unacceptable and must be
495// fixed. The one exception to this is that normal roundoff errors due to the inability of shorter floating point types to represent longer
496// floating point numbers are ignored:
497//
498// longVariable = DemoteTo<Sint32>(kVictor, doubleVariable);
499// This case is OK only if the value in doubleVariable is constrained to be in the range MINLONG to MAXLONG and has no
500// fractional component. e.g. it's illegal to pass 10.5 in doubleVariable.
501//
502// longVariable = DemoteTo<Sint32>(kVictor, Round(doubleVariable));
503// longVariable = DemoteTo<Sint32>(kVictor, Truncate(doubleVariable));
504// This is more likely the correct way to approach this problem as you are guaranteeing that there is no fractional component.
505//
506// longVariable = DemoteTo<Sint32>(kVictor, PinTo<Sint32>(kVictor, doubleVariable));
507// This specifies that the value be pinned either to the maximum or minimum of the destination type's range
508// if it is outside that range.
509
510// NOTE: The Round and Truncate functions are defined in BasicMath.X.h
511
512#include "GSDebug.h"
513#include <typeinfo>
514#include <limits>
515
516#include <sstream>
517
518
519#if GS_WIN
520#define force_inline __forceinline
521
522#else // mac
523
524#define force_inline inline
525#endif
526
527Boolean DoublesAreNotNearlyEqual(double n1, double n2);
528
529force_inline double fastFabs(double d) {return (d >= 0) ? d : -d; } // six times faster than fabs on Windows (and maybe Intel Mac?) // [MAF 12/22/05]
530
531//---------------------------------------------------------------------------------------
532template <typename PinType, typename FromType>
533#if !(GS_MAC && TEST)
534inline
535#endif
536FromType PinTo(const TProgrammer& TEST_ONLY(toWhom), const FromType fromValue)
537//
538// Description:
539// Templated function to pin the specified value to the range of the specified pin type.
540//
541// - Debug only behavior:
542// - Warns if type size is greater than maximum size
543// - Warns if identical types are being pinned between.
544// - Warns if pin type is larger than source type.
545//
546// Parameters:
547// toWhom - input - the programmer to whom any DSTOP messages will be addressed.
548// fromValue - input - the value to be pinned.
549//
550// Returns:
551// FromType - the pinned value.
552//
553// Created by Victor Long on 04/09/2004.
554//
555{
556
557 FromType toValue;
558 const size_t kMaxByteSize = 8;
559 size_t pinTypeSize = sizeof(PinType);
560 size_t fromTypeSize = sizeof(FromType);
561 bool mayPinValue = true;
562 PinType minPinValue;
563 PinType maxPinValue;
564
565 // Check to see if data type sizes are larger than maximum supported size
566 // and if so send DSTOP message.
567 if (pinTypeSize > kMaxByteSize ||
568 fromTypeSize > kMaxByteSize) {
569 mayPinValue = false;
570
571#if TEST
572 std::ostringstream outStream;
573
574 outStream << "PINNING WITH LARGER THAN SUPPORTED TYPE. PLEASE STOP AND EVALUATE." << std::endl;
575 outStream << std::endl;
576 outStream << "Pinning has occured where the size of one or both " << std::endl;
577 outStream << "of the source and pin types is greater " << std::endl;
578 outStream << "than the pinning function's maximum supported size " << std::endl;
579 outStream << "of " << kMaxByteSize << " bytes." << std::endl; //-V128
580 outStream << std::endl;
581 outStream << "Please remove the use of this pinning function," << std::endl;
582 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
583 outStream << std::endl << std::ends;
584
585 DSTOP((toWhom, "%s", outStream.str().c_str()));
586#endif
587 }
588 // Check to see if data types are identical
589 // and if so send DSTOP message.
590 else if (typeid(FromType) == typeid(PinType)) {
591 mayPinValue = false;
592
593#if TEST
594 std::ostringstream outStream;
595
596 outStream << "PINNING BETWEEN IDENTICAL TYPES. PLEASE STOP AND EVALUATE." << std::endl;
597 outStream << std::endl;
598 outStream << "Pinning has occurred where no pin should be required." << std::endl;
599 outStream << std::endl;
600 outStream << "Please remove the use of this pinning function," << std::endl;
601 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
602 outStream << std::endl << std::ends;
603
604 DSTOP((toWhom, "%s", outStream.str().c_str()));
605#endif
606 }
607 // Check to see if casting results in promotion
608 // and if so send DSTOP message.
609 else if (!(std::numeric_limits<FromType>::is_signed && !std::numeric_limits<PinType>::is_signed) &&
610 sizeof(PinType) > sizeof(FromType)) {
611 mayPinValue = false;
612
613#if TEST
614 std::ostringstream outStream;
615
616 outStream << "PINNING TO LARGER TYPE. PLEASE STOP AND EVALUATE." << std::endl;
617 outStream << std::endl;
618 outStream << "Pinning has occured where no pin should be required." << std::endl;
619 outStream << std::endl;
620 outStream << "Please remove the use of this pinning function," << std::endl;
621 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
622 outStream << std::endl << std::ends;
623
624 DSTOP((toWhom, "%s", outStream.str().c_str()));
625#endif
626 }
627
628 maxPinValue = std::numeric_limits<PinType>::max ();
629
630 if (std::numeric_limits<PinType>::is_integer) {
631 minPinValue = std::numeric_limits<PinType>::min ();
632 }
633 else {
634 minPinValue = -std::numeric_limits<PinType>::max ();
635 }
636
637 if (mayPinValue &&
638 fromValue > maxPinValue) {
639 toValue = maxPinValue;
640 }
641 else if (mayPinValue &&
642 fromValue < minPinValue) {
643 toValue = minPinValue;
644 }
645 else {
646 toValue = fromValue;
647 }
648
649 return toValue;
650}
651
652#if TEST
653// Check for floating point loss during DemoteTo. RBerge 08/27/2013.
654//
655// Split from DemoteTo so DemoteTo works with x64 data types.
656// If needed, this can be specialized so e.g. OtherType == Uint64 is a noop, to prevent compiler warning
657template <typename RealType, typename OtherType>
658#if !(GS_MAC && TEST)
659inline
660#endif
661bool DemotionDoubleTest(const RealType& realValue, const OtherType& otherValue)
662{
663 #if _WINDOWS
664 #pragma warning ( push )
665 #pragma warning( disable : 4244 ) // conversion from 'size_t' to 'double', possible loss of data. The check itself will tell us.
666 #endif
667 return DoublesAreNotNearlyEqual (realValue, otherValue);
668 #if _WINDOWS
669 #pragma warning ( pop )
670 #endif
671}
672#endif
673
674//---------------------------------------------------------------------------------------
675template <typename ToType, typename FromType>
676#if !(GS_MAC && TEST)
677inline
678#endif
679ToType DemoteTo(const TProgrammer& TEST_ONLY(toWhom), const FromType fromValue)
680//
681// Description:
682// Templated function to cast one data type to another.
683//
684// - Debug only behavior:
685// - Warns if type size is greater than maximum size
686// - Warns if identical types are being cast between.
687// - Warns if value is actually being promoted, not demoted.
688// - Warns if loss of data has occurred.
689//
690// Parameters:
691// toWhom - input - the programmer to whom any DSTOP messages will be addressed.
692// fromValue - input - the value to be cast from.
693//
694// Returns:
695// ToType - the value of the cast input value.
696//
697// Created by Victor Long on 03/31/2004.
698//
699{
700 ToType toValue;
701
702 // The input value is ALWAYS cast and returned.
703 // This is to preserve existing casting behavior where this function is used.
704 toValue = (ToType) fromValue;
705
706#if TEST
707 // This debug only section evaluates the casting operation
708 // for certain problems (see function description above).
709
710 const size_t kMaxByteSize = 8;
711 size_t toTypeSize = sizeof(ToType);
712 size_t fromTypeSize = sizeof(FromType);
713 bool castingResultsInLossOfData = false;
714
715 // Check to see if data type sizes are larger than maximum supported size
716 // and if so send DSTOP message.
717 if (toTypeSize > kMaxByteSize ||
718 fromTypeSize > kMaxByteSize) {
719 std::ostringstream outStream;
720
721 outStream << "CASTING WITH LARGER THAN SUPPORTED TYPE. PLEASE STOP AND EVALUATE." << std::endl;
722 outStream << std::endl;
723 outStream << "Casting has occured where the size of one or both " << std::endl;
724 outStream << "of the source and destination types is greater " << std::endl;
725 outStream << "than the casting function's maximum supported size " << std::endl;
726 outStream << "of " << kMaxByteSize << " bytes." << std::endl; //-V128
727 outStream << std::endl;
728 outStream << "Please remove the use of this casting function," << std::endl;
729 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
730 outStream << std::endl;
731 outStream << "Cast of:" << std::endl;
732 outStream << std::endl;
733 outStream << " " << typeid(FromType).name() << " to " << typeid(ToType).name() << std::endl;
734 outStream << std::endl << std::ends;
735
736 DSTOP((toWhom, "%s", outStream.str().c_str()));
737 }
738 else if ((typeid(FromType) == typeid(ToType)) && (sizeof(SintptrT) == sizeof(FromType)) && (sizeof(Sint32) == sizeof(ToType))) {
739 // For x32, quietly allow SintptrT demote to (same size) Sint32.
740 // For x64, they're different sizes, so this case can't be hit
741 }
742 // Check to see if data types are identical
743 // and if so send DSTOP message.
744 else if (typeid(FromType) == typeid(ToType)) {
745 std::ostringstream outStream;
746
747 outStream << "CASTING BETWEEN IDENTICAL TYPES. PLEASE STOP AND EVALUATE." << std::endl;
748 outStream << std::endl;
749 outStream << "Casting has occured where no cast should be required." << std::endl;
750 outStream << std::endl;
751 outStream << "Please remove the use of this casting function," << std::endl;
752 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
753 outStream << std::endl;
754 outStream << "Cast of:" << std::endl;
755 outStream << std::endl;
756 outStream << " " << typeid(FromType).name() << " to " << typeid(ToType).name() << std::endl;
757 outStream << std::endl << std::ends;
758
759 DSTOP((toWhom, "%s", outStream.str().c_str()));
760 }
761 // Check to see if casting results in promotion
762 // and if so send DSTOP message.
763 else if (!(std::numeric_limits<FromType>::is_signed && !std::numeric_limits<ToType>::is_signed) &&
764 sizeof(ToType) > sizeof(FromType)) {
765 std::ostringstream outStream;
766
767 outStream << "CASTING RESULTS IN PROMOTION. PLEASE STOP AND EVALUATE." << std::endl;
768 outStream << std::endl;
769 outStream << "Casting has occured where no cast should be required." << std::endl;
770 outStream << std::endl;
771 outStream << "Please remove the use of this casting function," << std::endl;
772 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
773 outStream << std::endl;
774 outStream << "Cast of:" << std::endl;
775 outStream << std::endl;
776 outStream << " " << typeid(FromType).name() << " to " << typeid(ToType).name() << std::endl;
777 outStream << std::endl << std::ends;
778
779 DSTOP((toWhom, "%s", outStream.str().c_str()));
780 }
781
782 // Always check for loss of data due to casting
783 // and if so send DSTOP message.
784 if (std::numeric_limits<FromType>::is_integer || std::numeric_limits<ToType>::is_integer) {
785 if (fromValue != toValue) {
786 castingResultsInLossOfData = true;
787 }
788 }
789 // check if floating point loss.
790 // X64 RBerge - Split out to a separate template so template instantiation isn't blindly casting e.g. Uint64 to double when compiling these statements
791 else if (std::numeric_limits<FromType>::is_integer && !std::numeric_limits<ToType>::is_integer && DemotionDoubleTest (toValue, fromValue)) {
792 castingResultsInLossOfData = true;
793 }
794 else if (std::numeric_limits<ToType>::is_integer && !std::numeric_limits<FromType>::is_integer && DemotionDoubleTest (fromValue, toValue)) {
795 castingResultsInLossOfData = true;
796 }
797
798 if (castingResultsInLossOfData) {
799 std::ostringstream outStream;
800
801 outStream << "CASTING RESULTS IN LOSS OF DATA. PLEASE STOP AND EVALUATE." << std::endl;
802 outStream << std::endl;
803 outStream << "Casting has caused a loss of data." << std::endl;
804 outStream << std::endl;
805 outStream << "Please evaluate this cast to determine what may be done to fix this error," << std::endl;
806 outStream << "or submit a bug that includes steps on how to reproduce this assert." << std::endl;
807 outStream << std::endl;
808 outStream << "Cast of:" << std::endl;
809 outStream << std::endl;
810 outStream << " " << typeid(FromType).name() << " to " << typeid(ToType).name() << std::endl;
811 outStream << std::endl;
812 outStream << "Has changed value from:" << std::endl;
813 outStream << std::endl;
814 outStream << " " << fromValue << " to " << toValue << std::endl << std::ends;
815
816 DSTOP((toWhom, "%s", outStream.str().c_str()));
817 }
818#endif // #if TEST #else !TEST
819
820 // Return cast input value.
821 return toValue;
822}
823
824template <typename ToType, typename FromType>
825#if !(GS_MAC && TEST)
826inline
827#endif
828ToType CastToPointer(const TProgrammer& TEST_ONLY(toWhom), const FromType fromValue){
829 ToType toValue;
830
831 toValue = reinterpret_cast<ToType>(static_cast<uintptr_t>(fromValue));
832 return toValue;
833}
834
835template <typename ToType, typename FromType>
836#if !(GS_MAC && TEST)
837inline
838#endif
839ToType CastFromPointer(const TProgrammer& TEST_ONLY(toWhom), const FromType fromValue){
840 ToType toValue;
841
842 toValue = static_cast<ToType>(reinterpret_cast<uintptr_t>(fromValue));
843 return toValue;
844}
845
846#endif // __cplusplus
847
848#endif // _GS_UTIL_
unsigned char Bool8
Definition GSTypes.h:79
uint16_t Uint16
Definition GSTypes.h:26
intptr_t SintptrT
Definition GSTypes.h:98
uintptr_t UintptrT
Definition GSTypes.h:99
int32_t Sint32
Definition GSTypes.h:36
int16_t Sint16
Definition GSTypes.h:35
uint64_t Uint64
Definition GSTypes.h:28
double Real64
Definition GSTypes.h:66
unsigned char Boolean
Definition GSTypes.h:111
uint32_t Uint32
Definition GSTypes.h:27
#define DSTOP(params)
Definition StdAfx.h:38
Boolean DoublesAreNotNearlyEqual(double n1, double n2)
Definition MCFloat.h:488