
/**********************************************************//**
 **
 ** @file base/types.h
 **
 ** Copyright (C) 2010  Xpace, LLC.  All rights reserved
 **
 ** www.xpace.net
 **
 **************************************************************/


#ifndef XPACE_TYPES_H
#define XPACE_TYPES_H

#include <cstdlib>  // for size_t
#include <memory>   // for autoptr
#include <cassert>
#include <cerrno>

#if defined _WIN32 && defined _DEBUG
  #define _CRTDBG_MAP_ALLOC
  #include <stdlib.h>
  #include <crtdbg.h>
//!!! have to do this bcs Qt uses free & realloc as function names
  #undef free
  #undef realloc 
#endif

/// import/export attribute, used only for Windows DLLs
#if !defined XPACE_EXPORT
# if !defined _WIN32 || defined XPACE_STATICLIB
#   define XPACE_EXPORT
# else
#   define XPACE_EXPORT __declspec(dllimport)
# endif
#endif

/// this definition requests an 'inline' that the compiler should honor
#if !defined FORCEINLINE
# if defined NDEBUG
#  if defined _WIN32
#    define FORCEINLINE __forceinline
#  elif defined __GNUC__
#    define FORCEINLINE inline __attribute__((always_inline))
#  else
#    error need to define FORCEINLINE for this compiler
#  endif
# else
#  define FORCEINLINE inline
# endif
#endif

/// %Xpace project main namespace
namespace Xpace 
{
  /// @name unsigned types
  //@{
  typedef unsigned char uchar;
  typedef uchar byte;
  typedef unsigned int uint;
  //@}

  /// @name explicity-sized types
  //@{
  typedef char int8;
  typedef unsigned char uint8;
  typedef short int16;
  typedef unsigned short uint16;
  typedef int int32;
  typedef unsigned int uint32;
  typedef long long int64;
  typedef unsigned long long uint64;
  //@}

  /// @name convert signed type to unsigned type
  //@{
  template<typename intType>
  struct Unsigned {};

  template<> struct Unsigned<int8>   { typedef uint8 Type; };
  template<> struct Unsigned<uint8>  { typedef uint8 Type; };
  template<> struct Unsigned<int16>  { typedef uint16 Type; };
  template<> struct Unsigned<uint16> { typedef uint16 Type; };
  template<> struct Unsigned<int32>  { typedef uint32 Type; };
  template<> struct Unsigned<uint32> { typedef uint32 Type; };
  template<> struct Unsigned<int64>  { typedef uint64 Type; };
  template<> struct Unsigned<uint64> { typedef uint64 Type; };

  #define UNSIGN(T) typename Unsigned<T>::Type
  //@}

  /// @name convert unsigned type to signed type
  //@{
  template<typename intType>
  struct Signed {};

  template<> struct Signed<int8>   { typedef int8 Type; };
  template<> struct Signed<uint8>  { typedef int8 Type; };
  template<> struct Signed<int16>  { typedef int16 Type; };
  template<> struct Signed<uint16> { typedef int16 Type; };
  template<> struct Signed<int32>  { typedef int32 Type; };
  template<> struct Signed<uint32> { typedef int32 Type; };
  template<> struct Signed<int64>  { typedef int64 Type; };
  template<> struct Signed<uint64> { typedef int64 Type; };

  #define SIGN(T) typename Signed<T>::Type
  //@}

  /// @name convert unsigned type to signed type, unsigned to signed
  //@{
  template<typename intType>
  struct ChangeSign {};

  template<> struct ChangeSign<int8>   { typedef uint8 Type; };
  template<> struct ChangeSign<uint8>  { typedef int8 Type; };
  template<> struct ChangeSign<int16>  { typedef uint16 Type; };
  template<> struct ChangeSign<uint16> { typedef int16 Type; };
  template<> struct ChangeSign<int32>  { typedef uint32 Type; };
  template<> struct ChangeSign<uint32> { typedef int32 Type; };
  template<> struct ChangeSign<int64>  { typedef uint64 Type; };
  template<> struct ChangeSign<uint64> { typedef int64 Type; };

  #define CHANGE_SIGN(T) typename ChangeSign<T>::Type
  //@}

  /// @name UTF char types
  //@{
  typedef unsigned char utf8_t;
  typedef unsigned short utf16_t;
  //@}

  /// @name fastest native types of at least 32 bits
  //@{
  #if defined _WIN64 || defined __LP64__
   // native 64-bit
   typedef int64 int_fast32;
   typedef uint64 uint_fast32;
  #else
   // native 32-bit
   typedef int32 int_fast32;
   typedef uint32 uint_fast32;
  #endif
  //@}

  /// A low-level const data holder 
  template <typename T>
  struct Ref
  {
    typedef T baseType;

    const T* data;          ///< first T
    size_t length;          ///< number of Ts

    /// constructor
    /// @param d first T
    /// @param len number of Ts
    Ref
      (const T* d = 0,
       size_t len = 0); 
  }; 

  typedef Ref<byte> BytesRef;

  /// A low-level data holder 
  template <typename T>
  struct Buf
  {
    T *const data;          ///< first T
    size_t length;          ///< number of Ts

    /// constructor
    /// @param d first T
    /// @param len number of Ts
    Buf
      (T* d,
       size_t len = 0); 
  }; 


  // ================================ STRINGS =================

  /// Raw Strings - just a pointer and length
  template <typename CH>
  struct RawString
  {
    typedef CH baseType;

    CH* data;
    size_t length;

    RawString
      (CH* d,
       size_t len) :
        data(d),
        length(len)
    {
    }

    RawString& operator=
      (RawString<CH>& rhs)
    {
      length = rhs.length;
      data = rhs.data;
      return *this;
    }

    bool operator==
      (const RawString<CH>& rhs)
      const
    {
      return (length == rhs.length) &&
             !memcmp(data, rhs.data, length);
    }

    bool operator!=
      (const RawString<CH>& rhs)
      const
    {
      return !(*this == rhs);
    }

    typedef CH charType;
  };

  typedef RawString<utf8_t>  String8;
  typedef RawString<utf16_t> String16;

  /// A string, which is Unicode UTF-16 and reference-counted
  class XPACE_EXPORT String
  {
  public:
    /// Construct a String from a UTF-8 array of 8-bit chars
    /// @param s the array of chars
    /// @param len if != 0, the length of the array; if 0, array is 0-terminated
    String
      (const utf8_t* s,
       size_t len = 0);  
 
    /// Construct a String from a UTF-16 array of 16-bit chars
    /// @param s the array of chars
    /// @param len if != 0, the length of the array; if 0, array is 0-terminated
    String
      (const utf16_t* s,
       size_t len = 0);  

    /// Construct a String from an array of 8-bit chars
    /// @param s the array of chars
    /// @param len if != 0, the length of the array; if 0, array is 0-terminated
    String
      (const char* s,
       size_t len = 0); 

    /// @return the length of the string, in chars
    size_t getLength
      ()
      const;

    /// convert a String into a (null-terminated) UTF-8, writing it into a buffer
    /// @param buf the buffer into which to write
    /// @param bufLen the lemgth of the buffer
    /// @return the buffer
    utf8_t* toUtf8
      (utf8_t* buf,
       size_t bufLen)
      const;
    
    /// @return the (null-terminated) UTF-16 representation of the string 
    const utf16_t* toUtf16
      ()
      const;

    #if defined QSTRING_H || defined DOCUMENTATION
    /// Convert a QString to a String
    /// @param s the source QString
    String
      (const QString&);
    /// Convert a (const) String into a (const) QString
    /// @return the QString
    operator const QString
      ()
      const;
    /// Convert a String into a QString
    /// @return the QString
    operator QString
      ();
    #endif

    /// Construct an empty string
    String
      ();
    String
      (const String&);
    String& operator=
      (const String&);
    ~String
      ();

    /// Make a string from a number
    /// @param n the source number
    /// @return *this
    String& setNum
      (int64 n);

    /// Get a number from a (base-10) string
    /// @param fillin true if the string could be converted, false if not
    /// @return value converted
    int64 getInt
      (bool* ok = 0)
      const;

    /// @return true is String is empty
    bool operator!
      ()
      const;

    /// @return true if this String matches rhs
    bool operator==
      (const String& rhs)
      const;

    /// @return true if this String does not match rhs
    bool operator!=
      (const String& rhs)
      const
    { 
      return !(*this == rhs); 
    };

    /// @return true if this String is less than rhs
    bool operator<
      (const String& rhs)
      const;

    /// @return true if theis String matches rhs w/o case sensitvity
    bool matchNoCase
      (const String& rhs)
      const;

    /// concatenate rhs to this string
    /// @param rhs the string to concatenate
    /// @return *this
    String& operator+=
      (const String& rhs);

  private :
    const void* impl;
  };

  // ================================ POWERS OF 10 ============

  template <typename T>
  class pow10
  {
  public:
    pow10
      (uint p) :
        n(vals[p])
    {
    }
    operator T
      ()
      const
    {
      return n;
    }
  private:
    const T n;
    static T vals[];
  };

  // ================================ TRACE ===================

  /// debugging
  class XPACE_EXPORT Trace
  {
  public:
    Trace
      (const char* ID,
       const char* format = 0,
       ...);
    ~Trace
      ();

    static void Msg
      (const char* format = 0,
       ...);

  #if defined _TRACE || defined DOCUMENTATION
  private:
    String id;
  #endif
  };

  // ================================ CHECKED TYPE CONVERSION ===

  /// checked loss-of-precision cast
  template <typename TO, typename FROM>
  inline TO narrow_to
    (FROM from)
  {
    assert(FROM(TO(from)) == from);
    return TO(from);
  }

  // ============================================================
  // ============================================================
  // ============================================================

  template <typename T>
  inline
  Ref<T>::Ref
    (const T* d,
     size_t len) :
      data(d), 
      length(len)
  {
  }

  template <typename T>
  inline
  Buf<T>::Buf
    (T* d,
     size_t len) :
      data(d), 
      length(len)
  {
  }

  #ifndef _TRACE
  inline
  Trace::Trace
    (const char* /*ID*/,
     const char*,
     ...)
  {
  }

  inline
  Trace::~Trace
    ()
  {
  }

  inline
  void Trace::Msg
    (const char*,
     ...)
  {
  }
  #endif

#if !defined(_WIN32)
  // nonstandard MS library functions supplied in namespace
  // Xpace on other platforms
  int64 _atoi64(const char*);
  int64 _wtoi64(const wchar_t*);
  int swprintf_s(wchar_t*, size_t, const wchar_t*, ...);
  typedef int errno_t;
  errno_t _itow_s(int, wchar_t*, size_t, int);
  errno_t _i64tow_s(int64, wchar_t*, size_t, int);
  errno_t wmemmove_s(wchar_t*, size_t, const wchar_t*, size_t);
#endif

} //  namespace Xpace

#endif

