/***************************************************************************************************

  Zyan Core Library (Zyan-C)

  Original Author : Florian Bernd, Joel Hoener

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.

***************************************************************************************************/

/**
 * @file
 * Includes and defines some default data types.
 */

#ifndef ZYCORE_TYPES_H
#define ZYCORE_TYPES_H

#include "zydis/Zycore/Defines.h"

/* ============================================================================================== */
/* Integer types                                                                                  */
/* ============================================================================================== */

#if defined(ZYAN_NO_LIBC) || \
    (defined(ZYAN_MSVC) && defined(ZYAN_KERNEL)) // The WDK LibC lacks stdint.h.
    // No LibC mode, use compiler built-in types / macros.
#   if defined(ZYAN_MSVC) || defined(ZYAN_ICC)
        typedef unsigned __int8                 ZyanU8;
        typedef unsigned __int16                ZyanU16;
        typedef unsigned __int32                ZyanU32;
        typedef unsigned __int64                ZyanU64;
        typedef   signed __int8                 ZyanI8;
        typedef   signed __int16                ZyanI16;
        typedef   signed __int32                ZyanI32;
        typedef   signed __int64                ZyanI64;
#       if _WIN64
           typedef ZyanU64                      ZyanUSize;
           typedef ZyanI64                      ZyanISize;
           typedef ZyanU64                      ZyanUPointer;
           typedef ZyanI64                      ZyanIPointer;
#       else
           typedef ZyanU32                      ZyanUSize;
           typedef ZyanI32                      ZyanISize;
           typedef ZyanU32                      ZyanUPointer;
           typedef ZyanI32                      ZyanIPointer;
#       endif
#   elif defined(ZYAN_GNUC)
#       ifdef __UINT8_TYPE__
            typedef __UINT8_TYPE__              ZyanU8;
#       else
            typedef unsigned char               ZyanU8;
#       endif
#       ifdef __UINT16_TYPE__
            typedef __UINT16_TYPE__             ZyanU16;
#       else
            typedef unsigned short int          ZyanU16;
#       endif
#       ifdef __UINT32_TYPE__
            typedef __UINT32_TYPE__             ZyanU32;
#       else
            typedef unsigned int                ZyanU32;
#       endif
#       ifdef __UINT64_TYPE__
            typedef __UINT64_TYPE__             ZyanU64;
#       else
#           if defined(__x86_64__) && !defined(__ILP32__)
                typedef unsigned long int       ZyanU64;
#           else
                typedef unsigned long long int  ZyanU64;
#           endif
#       endif
#       ifdef __INT8_TYPE__
            typedef __INT8_TYPE__               ZyanI8;
#       else
            typedef signed char                 ZyanI8;
#       endif
#       ifdef __INT16_TYPE__
            typedef __INT16_TYPE__              ZyanI16;
#       else
            typedef signed short int            ZyanI16;
#       endif
#       ifdef __INT32_TYPE__
            typedef __INT32_TYPE__              ZyanI32;
#       else
            typedef signed int                  ZyanI32;
#       endif
#       ifdef __INT64_TYPE__
            typedef __INT64_TYPE__              ZyanI64;
#       else
#           if defined(__x86_64__) && !defined( __ILP32__)
                typedef signed long int         ZyanI64;
#           else
                typedef signed long long int    ZyanI64;
#           endif
#       endif
#       ifdef __SIZE_TYPE__
            typedef __SIZE_TYPE__               ZyanUSize;
#       else
            typedef long unsigned int           ZyanUSize;
#       endif
#       ifdef __PTRDIFF_TYPE__
            typedef __PTRDIFF_TYPE__            ZyanISize;
#       else
            typedef long int                    ZyanISize;
#       endif
#       ifdef __UINTPTR_TYPE__
            typedef __UINTPTR_TYPE__            ZyanUPointer;
#       else
#           if defined(__x86_64__) && !defined( __ILP32__)
                typedef unsigned long int       ZyanUPointer;
#           else
                typedef unsigned int            ZyanUPointer;
#           endif
#       endif
#       ifdef __INTPTR_TYPE__
            typedef __INTPTR_TYPE__             ZyanIPointer;
#       else
#           if defined(__x86_64__) && !defined( __ILP32__)
                typedef long int                ZyanIPointer;
#           else
                typedef int                     ZyanIPointer;
#           endif
#       endif
#   else
#       error "Unsupported compiler for no-libc mode."
#   endif

#   if defined(ZYAN_MSVC)
#       define ZYAN_INT8_MIN            (-127i8 - 1)
#       define ZYAN_INT16_MIN           (-32767i16 - 1)
#       define ZYAN_INT32_MIN           (-2147483647i32 - 1)
#       define ZYAN_INT64_MIN           (-9223372036854775807i64 - 1)
#       define ZYAN_INT8_MAX            127i8
#       define ZYAN_INT16_MAX           32767i16
#       define ZYAN_INT32_MAX           2147483647i32
#       define ZYAN_INT64_MAX           9223372036854775807i64
#       define ZYAN_UINT8_MAX           0xffui8
#       define ZYAN_UINT16_MAX          0xffffui16
#       define ZYAN_UINT32_MAX          0xffffffffui32
#       define ZYAN_UINT64_MAX          0xffffffffffffffffui64
#   else
#       ifdef __INT8_MAX__
#           define ZYAN_INT8_MAX        __INT8_MAX__
#       else
#           define ZYAN_INT8_MAX        (127)
#       endif
#       define ZYAN_INT8_MIN            (-ZYAN_INT8_MAX - 1)
#       ifdef __INT16_MAX__
#           define ZYAN_INT16_MAX       __INT16_MAX__
#       else
#           define ZYAN_INT16_MAX       (32767)
#       endif
#       define ZYAN_INT16_MIN           (-ZYAN_INT16_MAX - 1)
#       ifdef __INT32_MAX__
#           define ZYAN_INT32_MAX       __INT32_MAX__
#       else
#           define ZYAN_INT32_MAX       (2147483647)
#       endif
#       define ZYAN_INT32_MIN           (-ZYAN_INT32_MAX - 1)
#       ifdef __INT64_MAX__
#           define ZYAN_INT64_MAX       __INT64_MAX__
#       else
#           if defined(__x86_64__) && !defined( __ILP32__)
#               define ZYAN_INT64_MAX   (9223372036854775807L)
#           else
#               define ZYAN_INT64_MAX   (9223372036854775807LL)
#           endif
#       endif
#       define ZYAN_INT64_MIN           (-ZYAN_INT64_MAX - 1)
#       ifdef __UINT8_MAX__
#           define ZYAN_UINT8_MAX       __UINT8_MAX__
#       else
#           define ZYAN_UINT8_MAX       (255)
#       endif
#       ifdef __UINT16_MAX__
#           define ZYAN_UINT16_MAX      __UINT16_MAX__
#       else
#           define ZYAN_UINT16_MAX      (65535)
#       endif
#       ifdef __UINT32_MAX__
#           define ZYAN_UINT32_MAX      __UINT32_MAX__
#       else
#           define ZYAN_UINT32_MAX      (4294967295U)
#       endif
#       ifdef __UINT64_MAX__
#           define ZYAN_UINT64_MAX      __UINT64_MAX__
#       else
#           if defined(__x86_64__) && !defined( __ILP32__)
#               define ZYAN_UINT64_MAX  (18446744073709551615UL)
#           else
#               define ZYAN_UINT64_MAX  (18446744073709551615ULL)
#           endif
#       endif
#   endif
#else
    // If is LibC present, we use stdint types.
#   include <stdint.h>
#   include <stddef.h>
    typedef uint8_t   ZyanU8;
    typedef uint16_t  ZyanU16;
    typedef uint32_t  ZyanU32;
    typedef uint64_t  ZyanU64;
    typedef int8_t    ZyanI8;
    typedef int16_t   ZyanI16;
    typedef int32_t   ZyanI32;
    typedef int64_t   ZyanI64;
    typedef size_t    ZyanUSize;
    typedef ptrdiff_t ZyanISize;
    typedef uintptr_t ZyanUPointer;
    typedef intptr_t  ZyanIPointer;

#   define ZYAN_INT8_MIN         INT8_MIN
#   define ZYAN_INT16_MIN        INT16_MIN
#   define ZYAN_INT32_MIN        INT32_MIN
#   define ZYAN_INT64_MIN        INT64_MIN
#   define ZYAN_INT8_MAX         INT8_MAX
#   define ZYAN_INT16_MAX        INT16_MAX
#   define ZYAN_INT32_MAX        INT32_MAX
#   define ZYAN_INT64_MAX        INT64_MAX
#   define ZYAN_UINT8_MAX        UINT8_MAX
#   define ZYAN_UINT16_MAX       UINT16_MAX
#   define ZYAN_UINT32_MAX       UINT32_MAX
#   define ZYAN_UINT64_MAX       UINT64_MAX
#endif

// Verify size assumptions.
ZYAN_STATIC_ASSERT(sizeof(ZyanU8      ) == 1            );
ZYAN_STATIC_ASSERT(sizeof(ZyanU16     ) == 2            );
ZYAN_STATIC_ASSERT(sizeof(ZyanU32     ) == 4            );
ZYAN_STATIC_ASSERT(sizeof(ZyanU64     ) == 8            );
ZYAN_STATIC_ASSERT(sizeof(ZyanI8      ) == 1            );
ZYAN_STATIC_ASSERT(sizeof(ZyanI16     ) == 2            );
ZYAN_STATIC_ASSERT(sizeof(ZyanI32     ) == 4            );
ZYAN_STATIC_ASSERT(sizeof(ZyanI64     ) == 8            );
ZYAN_STATIC_ASSERT(sizeof(ZyanUSize   ) == sizeof(void*)); // TODO: This one is incorrect!
ZYAN_STATIC_ASSERT(sizeof(ZyanISize   ) == sizeof(void*)); // TODO: This one is incorrect!
ZYAN_STATIC_ASSERT(sizeof(ZyanUPointer) == sizeof(void*));
ZYAN_STATIC_ASSERT(sizeof(ZyanIPointer) == sizeof(void*));

// Verify signedness assumptions (relies on size checks above).
ZYAN_STATIC_ASSERT((ZyanI8 )-1 >> 1 < (ZyanI8 )((ZyanU8 )-1 >> 1));
ZYAN_STATIC_ASSERT((ZyanI16)-1 >> 1 < (ZyanI16)((ZyanU16)-1 >> 1));
ZYAN_STATIC_ASSERT((ZyanI32)-1 >> 1 < (ZyanI32)((ZyanU32)-1 >> 1));
ZYAN_STATIC_ASSERT((ZyanI64)-1 >> 1 < (ZyanI64)((ZyanU64)-1 >> 1));

/* ============================================================================================== */
/* Pointer                                                                                        */
/* ============================================================================================== */

/**
 * Defines the `ZyanVoidPointer` data-type.
 */
typedef void* ZyanVoidPointer;

/**
 * Defines the `ZyanConstVoidPointer` data-type.
 */
typedef const void* ZyanConstVoidPointer;

#define ZYAN_NULL ((void*)0)

/* ============================================================================================== */
/* Logic types                                                                                    */
/* ============================================================================================== */

/* ---------------------------------------------------------------------------------------------- */
/* Boolean                                                                                        */
/* ---------------------------------------------------------------------------------------------- */

#define ZYAN_FALSE 0u
#define ZYAN_TRUE  1u

/**
 * Defines the `ZyanBool` data-type.
 *
 * Represents a default boolean data-type where `0` is interpreted as `false` and all other values
 * as `true`.
 */
typedef ZyanU8 ZyanBool;

/* ---------------------------------------------------------------------------------------------- */
/* Ternary                                                                                        */
/* ---------------------------------------------------------------------------------------------- */

/**
 * Defines the `ZyanTernary` data-type.
 *
 * The `ZyanTernary` is a balanced ternary type that uses three truth values indicating `true`,
 * `false` and an indeterminate third value.
 */
typedef ZyanI8 ZyanTernary;

#define ZYAN_TERNARY_FALSE    (-1)
#define ZYAN_TERNARY_UNKNOWN  0x00
#define ZYAN_TERNARY_TRUE     0x01

/* ============================================================================================== */
/* String types                                                                                   */
/* ============================================================================================== */

/* ---------------------------------------------------------------------------------------------- */
/* C-style strings                                                                                */
/* ---------------------------------------------------------------------------------------------- */

/**
 * Defines the `ZyanCharPointer` data-type.
 *
 * This type is most often used to represent null-terminated strings aka. C-style strings.
 */
typedef char* ZyanCharPointer;

/**
 * Defines the `ZyanConstCharPointer` data-type.
 *
 * This type is most often used to represent null-terminated strings aka. C-style strings.
 */
typedef const char* ZyanConstCharPointer;

/* ---------------------------------------------------------------------------------------------- */

/* ============================================================================================== */

#endif /* ZYCORE_TYPES_H */
