os_fixes.hpp

    1: #ifndef OS_FIXES_HPP
    2: #define OS_FIXES_HPP
    3: /*------------------------------------------------------------------------------
    4: 
    5:   Author:    Andy Rushton
    6:   Copyright: (c) Southampton University 1999-2004
    7:              (c) Andy Rushton           2004-2009
    8:   License:   BSD License, see ../docs/license.html
    9: 
   10:   Contains work arounds for OS or Compiler specific problems to try to make
   11:   them look more alike
   12: 
   13:   It is strongly recommended that this header be included as the first
   14:   #include in every source file
   15: 
   16:   ------------------------------------------------------------------------------*/
   17: 
   18: ////////////////////////////////////////////////////////////////////////////////
   19: // Problem with MicroSoft defining two different macros to identify Windows
   20: ////////////////////////////////////////////////////////////////////////////////
   21: 
   22: #if defined(_WIN32) || defined(_WIN32_WCE)
   23: #define MSWINDOWS
   24: #endif
   25: 
   26: ////////////////////////////////////////////////////////////////////////////////
   27: // Problems with unnecessary or unfixable compiler warnings
   28: ////////////////////////////////////////////////////////////////////////////////
   29: 
   30: #if defined(_MSC_VER)
   31: // Microsoft Visual Studio
   32: // shut up the following irritating warnings
   33: //   4275 - VC6, exported class was derived from a class that was not exported
   34: //   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)
   35: //   4305 - VC6, identifier type was converted to a smaller type
   36: //   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)
   37: //   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it
   38: //   4290 - VC6, C++ exception specification ignored
   39: //   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)
   40: //   4675 - VC7.1, "change" in function overload resolution _might_ have altered program
   41: //   4996 - VC8, 'xxxx' was declared deprecated
   42: #pragma warning(disable: 4275 4786 4305 4503 4309 4290 4800 4675 4996)
   43: #endif
   44: 
   45: #if defined(__BORLANDC__)
   46: // Borland
   47: // Shut up the following irritating warnings
   48: //   8008 - Condition is always true.
   49: //          Whenever the compiler encounters a constant comparison that (due to
   50: //          the nature of the value being compared) is always true or false, it
   51: //          issues this warning and evaluates the condition at compile time.
   52: //   8060 - Possibly incorrect assignment.
   53: //          This warning is generated when the compiler encounters an assignment
   54: //          operator as the main operator of a conditional expression (part of
   55: //          an if, while, or do-while statement). This is usually a
   56: //          typographical error for the equality operator.
   57: //   8066 - Unreachable code.
   58: //          A break, continue, goto, or return statement was not followed by a
   59: //          label or the end of a loop or function. The compiler checks while,
   60: //          do, and for loops with a constant test condition, and attempts to
   61: //          recognize loops that can't fall through.
   62: #pragma warn -8008
   63: #pragma warn -8060
   64: #pragma warn -8066
   65: #endif
   66: 
   67: ////////////////////////////////////////////////////////////////////////////////
   68: // Problems with redefinition of min/max in various different versions of library headers
   69: ////////////////////////////////////////////////////////////////////////////////
   70: 
   71: // The Windows headers define macros called max/min which conflict with the templates std::max and std::min.
   72: // So, to avoid conflicts, MS removed the std::max/min rather than fixing the problem!
   73: // From Visual Studio .NET (SV7, compiler version 13.00) the STL templates have been added correctly.
   74: // This fix switches off the macros and reinstates the STL templates for earlier versions (SV6).
   75: // Note that this could break MFC applications that rely on the macros (try it and see).
   76: 
   77: // For MFC compatibility, only undef min and max in non-MFC programs - some bits of MFC
   78: // use macro min/max in headers. For VC7 both the macros and template functions exist
   79: // so there is no real need for the undefs but to it anyway for consistency. So, if
   80: // using VC6 and MFC then template functions will not exist
   81: 
   82: // I've created extra template function definitions minimum/maximum that avoid all the problems above
   83: 
   84: #if defined(_MSC_VER) && !defined(_MFC_VER)
   85: #define NOMINMAX
   86: #undef max
   87: #undef min
   88: // replace missing template definitions in VC6
   89: #if defined(_MSC_VER) && (_MSC_VER < 1300)
   90: namespace std
   91: {
   92:   template<typename T> const T& max(const T& l, const T& r) {return l > r ? l : r;}
   93:   template<typename T> const T& min(const T& l, const T& r) {return l < r ? l : r;}
   94: }
   95: #endif
   96: #endif
   97: 
   98: template<typename T> const T& maximum(const T& l, const T& r) {return l > r ? l : r;}
   99: template<typename T> const T& minimum(const T& l, const T& r) {return l < r ? l : r;}
  100: 
  101: ////////////////////////////////////////////////////////////////////////////////
  102: // Problem with missing __FUNCTION__ macro
  103: ////////////////////////////////////////////////////////////////////////////////
  104: // this macro is used in debugging but was missing in Visual Studio prior to version 7
  105: // it also has a different name in Borland
  106: 
  107: #if defined(_MSC_VER) && (_MSC_VER < 1300)
  108: #define __FUNCTION__ 0
  109: #endif
  110: 
  111: #if defined(__BORLANDC__)
  112: #define __FUNCTION__ __FUNC__
  113: #endif
  114: 
  115: ////////////////////////////////////////////////////////////////////////////////
  116: // Problems with differences between namespaces
  117: ////////////////////////////////////////////////////////////////////////////////
  118: 
  119: // problem in gcc pre-v3 where the sub-namespaces in std aren't present
  120: // this mean that the statement "using namespace std::rel_ops" created an error because the namespace didn't exist
  121: 
  122: // I've done a fix here that creates an empty namespace for this case, but I
  123: // do *not* try to move the contents of std::rel_ops into namespace std
  124: // This fix only works if you use "using namespace std::rel_ops" to bring in the template relational operators (e.g. != defined i.t.o. ==)
  125: 
  126: #if defined(__GNUC__)
  127: namespace std
  128: {
  129:   namespace rel_ops
  130:   {
  131:   }
  132: }
  133: #endif
  134: 
  135: ////////////////////////////////////////////////////////////////////////////////
  136: // Problems with the typename keyword
  137: ////////////////////////////////////////////////////////////////////////////////
  138: 
  139: // There are problems with using the 'typename' keyword. Technically, if you
  140: // use a type member of a template class (i.e. a type declared within the
  141: // template class by a local typedef), you need to tell the compiler that it
  142: // is a type name. This is because the compiler cannot work out whether a
  143: // member is a type, a method or a data field at compile time. However,
  144: // support for the typename keyword has traditionally been incomplete in both
  145: // gcc and Visual Studio. I have used macros to try to resolve this issue. The
  146: // macros add the keyword for compiler versions that require it and omit it
  147: // for compiler versions that do not support it
  148: 
  149: // There are five places where typename keywords cause problems:
  150: //
  151: //   1) in a typedef where a template class's member type is being mapped onto
  152: //      a type definition within another template class or function 
  153: //      e.g. template<typename T> fn () {
  154: //             typedef typename someclass<T>::member_type local_type;
  155: //                     ^^^^^^^^
  156: //      Note that the typename keyword is only required when the type is of this form - a member of a template class
  157: //      This situation is handled by the macro TYPEDEF_TYPENAME
  158: //
  159: //   2) in a function parameter declaration, with similar rules to the above
  160: //      e.g. template<typename T> fn (typename someclass<T>::member_type)
  161: //                                    ^^^^^^^^
  162: //      Note that the typename keyword is only required when the type is of this form - a member of a template class
  163: //      This situation is handled by the macro PARAMETER_TYPENAME
  164: //
  165: //   3) in instantiating a template, the parameter to the template, with similar rules to the above
  166: //      e.g. template_class<typename someclass<T>::member_type>
  167: //                          ^^^^^^^^
  168: //      Note that the typename keyword is only required when the type is of this form - a member of a template class
  169: //      This situation is handled by the macro TEMPLATE_TYPENAME
  170: //   4) Return expressions
  171: //      e.g. return typename ntree<T>::const_iterator(this,m_root);
  172: //                  ^^^^^^^^
  173: //      Note that this typename is only required when the return type is a member of a template class
  174: //   5) Creating temporary objects when passing arguments to a function or constructor
  175: //      e.g. return typename ntree<T>::const_prefix_iterator(typename ntree<T>::const_iterator(this,m_root));
  176: //                                                           ^^^^^^^^
  177: //      Note that the typename keyword is only required when the temporary's type is a member of a template class
  178: 
  179: // default values, overridden for individual problem cases below
  180: #define TYPEDEF_TYPENAME typename
  181: #define PARAMETER_TYPENAME typename
  182: #define TEMPLATE_TYPENAME typename
  183: #define RETURN_TYPENAME typename
  184: #define TEMPORARY_TYPENAME typename
  185: 
  186: #if defined(__GNUC__)
  187: // GCC 
  188: //   - pre-version 3 didn't handle typename in any of these cases
  189: //   - version 3 onwards, typename is required for all three cases as per default
  190: #if __GNUC__ < 3
  191: // gcc prior to v3
  192: #undef TYPEDEF_TYPENAME
  193: #define TYPEDEF_TYPENAME
  194: #undef PARAMETER_TYPENAME
  195: #define PARAMETER_TYPENAME
  196: #undef TEMPLATE_TYPENAME
  197: #define TEMPLATE_TYPENAME
  198: #undef RETURN_TYPENAME
  199: #define RETURN_TYPENAME
  200: #undef TEMPORARY_TYPENAME
  201: #define TEMPORARY_TYPENAME
  202: #endif
  203: #endif
  204: 
  205: #if defined(_MSC_VER)
  206: // Visual Studio
  207: //   - version 6 (compiler v.12) cannot handle typename in any of these cases
  208: //   - version 7 (.NET) (compiler v.13) requires a typename in a parameter specification but supports all
  209: //   - version 8 (2005) (compiler v.14) requires parameters and templates, supports all
  210: #if _MSC_VER < 1300
  211: // compiler version 12 and earlier
  212: #undef TYPEDEF_TYPENAME
  213: #define TYPEDEF_TYPENAME
  214: #undef PARAMETER_TYPENAME
  215: #define PARAMETER_TYPENAME
  216: #undef TEMPLATE_TYPENAME
  217: #define TEMPLATE_TYPENAME
  218: #undef RETURN_TYPENAME
  219: #define RETURN_TYPENAME
  220: #undef TEMPORARY_TYPENAME
  221: #define TEMPORARY_TYPENAME
  222: #endif
  223: #endif
  224: 
  225: ////////////////////////////////////////////////////////////////////////////////
  226: // problems with missing functions
  227: ////////////////////////////////////////////////////////////////////////////////
  228: 
  229: #if defined(_MSC_VER) || defined(__BORLANDC__)
  230: unsigned sleep(unsigned seconds);
  231: #else
  232: #include <unistd.h>
  233: #endif
  234: 
  235: ////////////////////////////////////////////////////////////////////////////////
  236: // Function for establishing endian-ness
  237: ////////////////////////////////////////////////////////////////////////////////
  238: // Different machine architectures store data using different byte orders.
  239: // This is referred to as Big- and Little-Endian Byte Ordering. 
  240: //
  241: // The issue is: where does a pointer to an integer type actually point?
  242: //
  243: // In both conventions, the address points to the left of the word but:
  244: // Big-Endian - The most significant byte is on the left end of a word
  245: // Little-Endian - The least significant byte is on the left end of a word
  246: //
  247: // Bytes are addressed left to right, so in big-endian order byte 0 is the
  248: // msB, whereas in little-endian order byte 0 is the lsB. For example,
  249: // Intel-based machines store data in little-endian byte order so byte 0 is
  250: // the lsB.
  251: //
  252: // This function establishes byte order at run-time
  253: 
  254: bool little_endian(void);
  255: 
  256: ////////////////////////////////////////////////////////////////////////////////
  257: #endif