/* Copyright (c) Microsoft Corporation. All rights reserved. */
#ifndef __BASE_INT64_H_
#define __BASE_INT64_H_ 1

/*** 64 bit integer support for the benefit of compilers that don't do it ***/
/* Defaults for compilers that do */

#if !defined(__INCLUDE_INT64_AGAIN)

#ifdef __BYTE_ORDER_IS_BIG_ENDIAN
struct _INT64          /* size is 8 */
{
    INT32 HighPart;
    UINT32 LowPart;
};

struct _UINT64         /* size is 8 */
{
    UINT32 HighPart;
    UINT32 LowPart;
};

#define Int64Initializer(_hi32_,_lo32_) { _hi32_, _lo32_ }

#else
struct _INT64          /* size is 8 */
{
    UINT32 LowPart;
    INT32 HighPart;
};

struct _UINT64         /* size is 8 */
{
    UINT32 LowPart;
    UINT32 HighPart;
};

#define Int64Initializer(_hi32_,_lo32_) { _lo32_, _hi32_ }

#endif /* byte order */
#endif /* __INCLUDE_INT64_AGAIN */

#if defined(__NO_BUILTIN_INT64)    /* no compiler support */

#define Int64FromHighAndLow(_i64_,_hi32_,_lo32_) \
    { \
      (_i64_).LowPart = _lo32_; \
      (_i64_).HighPart = _hi32_; \
    }

#define Uint64High32Bits(_u64_)  ((_u64_).HighPart)
#define Uint64Low32Bits(_u64_)   ((_u64_).LowPart)

#define Int32ToInt64(_i64_,_i32_) \
    { \
      (_i64_).LowPart = (UINT32) _i32_; \
      (_i64_).HighPart = ((_i32_) < 0)  ? -1 : 0; \
    }

#define Uint32ToUint64(_u64_,_u32_) \
    { \
      (_u64_).LowPart = _u32_; \
      (_u64_).HighPart = 0; \
    }

#define Int64ToInt32(_i64_) (INT32)((_i64_).LowPart)
#define Uint64ToUint32(_u64_) ((_u64_).LowPart)
#define Int64ToUint64(_x_) (*(UINT64*)&(_x_))
#define Uint64ToInt64(_x_) (*(INT64*)&(_x_))

#define Int64Equal(_a_,_b_) \
    (((_a_).LowPart == (_b_).LowPart) && ((_a_).HighPart == (_b_).HighPart))
#define Int64Less(_a_,_b_) \
    (((_a_).HighPart < (_b_).HighPart) || \
     (((_a_).HighPart == (_b_).HighPart) && ((_a_).LowPart < (_b_).LowPart)))
#define Uint64Less(_a_,_b_) Int64Less((_a_), (_b_))
#define Int64IsZero(_a_) \
    (((_a_).HighPart == 0) && ((_a_).LowPart == 0))
#define Int64IsNegative(_a_) \
    ((_a_).HighPart < 0)
#define Int64IsNotPositive(_a_) \
    (Int64IsNegative(_a_) || Int64IsZero(_a_))

#define Int64SubtractInt32(_a_,_b_) Int64AddInt32(_a_, -(_b_))

EXTERN_C INT64  Int64Add(INT64 a, INT64 b);
EXTERN_C UINT64 Uint64Add(UINT64 a, UINT64 b);
EXTERN_C INT64  Int64AddInt32(INT64 a, INT32 b);
EXTERN_C UINT64 Uint64AddUint32(UINT64 a, UINT32 b);
EXTERN_C INT64  Int64Subtract(INT64 a, INT64 b);
EXTERN_C UINT64 Uint64Subtract(UINT64 a, UINT64 b);
EXTERN_C UINT64 Uint64SubtractUint32(UINT64 a, UINT32 b);
EXTERN_C INT64  Int64LShift(INT64 a, INT32 n);
EXTERN_C INT64  Int64RShift(INT64 a, INT32 n);
EXTERN_C UINT64 Uint64LShift(UINT64 a, INT32 n);
EXTERN_C UINT64 Uint64RShift(UINT64 a, INT32 n);
EXTERN_C INT64  Int64Or(INT64 a, INT64 b);
EXTERN_C INT64  Int64And(INT64 a, INT64 b);
EXTERN_C INT64  Int64Xor(INT64 a, INT64 b);
EXTERN_C UINT64 Uint64Or(UINT64 a, UINT64 b);
EXTERN_C UINT64 Uint64And(UINT64 a, UINT64 b);
EXTERN_C UINT64 Uint64Xor(UINT64 a, UINT64 b);
EXTERN_C INT64  Int64TimesInt32( INT64 a, INT32 b);
EXTERN_C INT64  Int64TimesInt64( INT64 a, INT64 b);
EXTERN_C UINT64 Uint64TimesUint32( UINT64 a, UINT32 b);
EXTERN_C UINT64 Uint64TimesUint64( UINT64 a, UINT64 b);
EXTERN_C INT64  Int64DividedByInt32( INT64 a, INT32 b);
EXTERN_C INT64  Int64DividedByInt64( INT64 a, INT64 b);
EXTERN_C UINT64 Uint64DividedByUint32( UINT64 a, UINT32 b);
EXTERN_C UINT64 Uint64DividedByUint64( UINT64 a, UINT64 b);
EXTERN_C UINT64 Uint64ModulusUint32( UINT64 a, UINT32 b);
EXTERN_C UINT64 Uint64ModulusUint64( UINT64 a, UINT64 b);
EXTERN_C INT64 Int64ModulusInt32( INT64 a, INT32 b);
EXTERN_C INT64 Int64ModulusInt64( INT64 a, INT64 b);

#define TimeIsNotPositive Int64IsNotPositive
#define TimeIsPositive(_t_) (!Int64IsNotPositive(_t_))
#ifndef TimeNeeds32Bits         /* allow machdep override */
#define TimeNeeds32Bits(_t_) ((_t_).HighPart != 0)
#endif

/* constants */
EXTERN_C const INT64 INT64_ZERO;
EXTERN_C const UINT64 UINT64_ZERO;
EXTERN_C const UINT64 UINT64_MAX;

#else   /* use compiler support (default) */

#undef Int64Initializer

#define Int64FromHighAndLow(_i64_,_hi32_,_lo32_) \
        _i64_ = (((UINT64)(UINT32)_lo32_) | (UINT64)(((INT64)_hi32_) << 32))

#define Int64Initializer(_hi32_,_lo32_) \
        (((UINT64)(UINT32)_lo32_) | (UINT64)(((INT64)_hi32_) << 32))

#define Uint64High32Bits(_u64_)  ((UINT32)((_u64_)>>32))
#define Uint64Low32Bits(_u64_)   ((UINT32)(_u64_))

#define Int32ToInt64(_i64_,_i32_) _i64_ = (INT64)_i32_
#define Uint32ToUint64(_u64_,_u32_) _u64_ = (UINT64)_u32_
#define Int64ToInt32(_i64_) ((INT32)(_i64_))
#define Uint64ToUint32(_u64_) ((UINT32)(_u64_))
#define Int64ToUint64(_x_) ((UINT64)(_x_))
#define Uint64ToInt64(_x_) ((INT64)(_x_))

#define Int64Equal(_a_,_b_) ((_a_) == (_b_))
#define Int64Less(_a_,_b_) ((_a_) < (_b_))
#define Uint64Less(_a_,_b_) Int64Less((_a_), (_b_))
#define Int64IsZero(_a_) ((_a_) == 0)
#define Int64IsNegative(_a_) ((_a_) < 0)
#define Int64IsNotPositive(_a_) ((_a_) <= 0)

#define Int64Add(_a_,_b_) ((_a_) + (_b_))
#define Uint64Add(_a_,_b_) Int64Add(_a_,_b_)
#define Int64AddInt32(_a_,_b_) ((INT64)((_a_) + (_b_)))
#define Uint64AddUint32(_a_,_b_) ((UINT64)((_a_) + (_b_)))
#define Int64Subtract(_a_,_b_) ((_a_) - (_b_))
#define Uint64Subtract(_a_,_b_) Int64Subtract(_a_,_b_)
#define Int64SubtractInt32(_a_,_b_) Int64AddInt32(_a_, -(_b_))
#define Uint64SubtractUint32(_a_,_b_) ((UINT64)((_a_) - (_b_)))
#define Int64LShift(_a_,_n_) ((INT64) ((_a_) << (_n_)))
#define Int64RShift(_a_,_n_) ((INT64) ((_a_) >> (_n_)))
#define Uint64LShift(_a_,_n_) ((UINT64) ((_a_) << (_n_)))
#define Uint64RShift(_a_,_n_) ((UINT64) ((_a_) >> (_n_)))
#define Int64Or(_a_,_b_) ((_a_) | (_b_))
#define Int64And(_a_,_b_) ((_a_) & (_b_))
#define Int64Xor(_a_,_b_) ((_a_) ^ (_b_))
#define Uint64Or(_a_,_b_) Int64Or(_a_,_b_)
#define Uint64And(_a_,_b_) Int64And(_a_,_b_)
#define Uint64Xor(_a_,_b_) Int64Xor(_a_,_b_)
#define Int64TimesInt32(_i64_,_i32_) ((INT64)((_i64_) * (_i32_)))
#define Int64TimesInt64(_i64a_,_i64b_) ((INT64)((_i64a_) * (_i64b_)))
#define Uint64TimesUint32(_i64_,_i32_) ((UINT64)((_i64_) * (_i32_)))
#define Uint64TimesUint64(_i64a_,_i64b_) ((UINT64)((_i64a_) * (_i64b_)))
#define Int64DividedByInt32(_i64_,_i32_) ((INT64)((_i64_) / (_i32_)))
#define Int64DividedByInt64(_i64a_,_i64b_) ((INT64)((_i64a_) / (_i64b_)))
#define Uint64DividedByUint32(_i64_,_i32_) ((UINT64)((_i64_) / (_i32_)))
#define Uint64DividedByUint64(_i64a_,_i64b_) ((UINT64)((_i64a_) / (_i64b_)))
#define Uint64ModulusUint32(_i64_,_i32_) ((UINT64)((_i64_) % (UINT32)(_i32_)))
#define Uint64ModulusUint64(_i64a_,_i64b_) ((UINT64)((_i64a_) % (UINT64)(_i64b_)))
#define Int64ModulusInt32(_i64_,_i32_) ((INT64)((_i64_) % (INT32)(_i32_)))
#define Int64ModulusInt64(_i64a_,_i64b_) ((INT64)((_i64a_) % (INT64)(_i64b_)))

#ifndef TimeNeeds32Bits         /* allow machdep override */
#define TimeNeeds32Bits(_t_) ((_t_) > (TIME)0x7fffffff)
#endif

/* constants */
#define UINT64_ZERO         ((UINT64)0)
#define UINT64_MAX         (~(UINT64)0)
#define INT64_ZERO          ((INT64)0)
#endif /* _MACHDEP_INT64 */

#if !defined(TimeEqual)         /* allow machdep override */
#define TimeEqual Int64Equal
#define TimeLess Int64Less
#define TimeAdd Int64Add
#define TimeSubtract Int64Subtract
#define TimeIsRelative Int64IsNegative
#define TimeIsNotPositive Int64IsNotPositive
#define TimeIsPositive(_t_) (!Int64IsNotPositive(_t_))
#endif /* TimeEqual */

#if !defined(INT64ADD)
#define INT64ADD(_r_,_p1_,_p2_)    _r_ = Int64Add((_p1_),(_p2_))
#define INT64SUB(_r_,_p1_,_p2_)    _r_ = Int64Subtract((_p1_),(_p2_))
#endif

/* Workaround for arm250 bug: can't have unpacked within packed but making all INT64 packed generates "Illegal JOP mode" */
#if !defined(__INCLUDE_INT64_AGAIN)
#if (defined(arm) && !defined(__GNUC__) && !defined(_MSC_VER))
typedef __packed struct { UINT32 LowPart; INT32 HighPart; } __PACKED_INT64;
typedef __packed struct { UINT32 LowPart; UINT32 HighPart; } __PACKED_UINT64;
#else
typedef INT64 __PACKED_INT64;
typedef UINT64 __PACKED_UINT64;
#endif
#endif

#endif /* __BASE_INT64_H_ */