// Sets up common environment for Shay Green's libraries.
// To change configuration options, modify blargg_config.h, not this file.

// Gb_Snd_Emu 0.2.0
#ifndef BLARGG_COMMON_H
#define BLARGG_COMMON_H

#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>

#undef BLARGG_COMMON_H
// allow blargg_config.h to #include blargg_common.h
#include "blargg_config.h"
#ifndef BLARGG_COMMON_H
#define BLARGG_COMMON_H

// BLARGG_RESTRICT: equivalent to restrict, where supported
#if __GNUC__ >= 3 || _MSC_VER >= 1100
#define BLARGG_RESTRICT __restrict
#else
#define BLARGG_RESTRICT
#endif

// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
// CONST_CAST( T,expr): Used in place of const_cast<T> (expr)
#ifndef STATIC_CAST
#if __GNUC__ >= 4
#define STATIC_CAST(T, expr) static_cast<T>(expr)
#define CONST_CAST(T, expr) const_cast<T>(expr)
#else
#define STATIC_CAST(T, expr) ((T)(expr))
#define CONST_CAST(T, expr) ((T)(expr))
#endif
#endif

// blargg_err_t (0 on success, otherwise error string)
#ifndef blargg_err_t
typedef const char *blargg_err_t;
#endif

// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
template <class T> class blargg_vector
{
        T *begin_;
        size_t size_;

        public:
        blargg_vector() : begin_(0), size_(0)
        {
        }
        ~blargg_vector()
        {
                free(begin_);
        }
        size_t size() const
        {
                return size_;
        }
        T *begin() const
        {
                return begin_;
        }
        T *end() const
        {
                return begin_ + size_;
        }
        blargg_err_t resize(size_t n)
        {
                // TODO: blargg_common.cpp to hold this as an outline function, ugh
                void *p = realloc(begin_, n * sizeof(T));
                if (p)
                        begin_ = (T *)p;
                else if (n > size_) // realloc failure only a problem if expanding
                        return "Out of memory";
                size_ = n;
                return 0;
        }
        void clear()
        {
                void *p = begin_;
                begin_ = 0;
                size_ = 0;
                free(p);
        }
        T &operator[](size_t n) const
        {
                assert(n <= size_); // <= to allow past-the-end value
                return begin_[n];
        }
};

#ifndef BLARGG_DISABLE_NOTHROW
// throw spec mandatory in ISO C++ if operator new can return NULL
#if __cplusplus >= 199711 || __GNUC__ >= 3
#define BLARGG_THROWS(spec) throw spec
#else
#define BLARGG_THROWS(spec)
#endif
#define BLARGG_DISABLE_NOTHROW                                                                     \
        void *operator new(size_t s) BLARGG_THROWS(())                                             \
        {                                                                                          \
                return malloc(s);                                                                  \
        }                                                                                          \
        void operator delete(void *p)                                                              \
        {                                                                                          \
                free(p);                                                                           \
        }
#define BLARGG_NEW new
#else
#include <new>
#define BLARGG_NEW new (std::nothrow)
#endif

// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
#define BLARGG_4CHAR(a, b, c, d)                                                                   \
        ((a & 0xFF) * 0x1000000 + (b & 0xFF) * 0x10000 + (c & 0xFF) * 0x100 + (d & 0xFF))

// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
#ifndef BOOST_STATIC_ASSERT
#ifdef _MSC_VER
// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
#define BOOST_STATIC_ASSERT(expr) void blargg_failed_(int(*arg)[2 / (int)!!(expr)-1])
#else
// Some other compilers fail when declaring same function multiple times in class,
// so differentiate them by line
#define BOOST_STATIC_ASSERT(expr) void blargg_failed_(int(*arg)[2 / !!(expr)-1][__LINE__])
#endif
#endif

// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
// compiler is assumed to support bool. If undefined, availability is determined.
#ifndef BLARGG_COMPILER_HAS_BOOL
#if defined(__MWERKS__)
#if !__option(bool)
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#elif defined(_MSC_VER)
#if _MSC_VER < 1100
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#elif defined(__GNUC__)
// supports bool
#elif __cplusplus < 199711
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#endif
#if defined(BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
// If you get errors here, modify your blargg_config.h file
typedef int bool;
const bool true = 1;
const bool false = 0;
#endif

// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough

#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
typedef long blargg_long;
#else
typedef int blargg_long;
#endif

#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
typedef unsigned long blargg_ulong;
#else
typedef unsigned blargg_ulong;
#endif

// BOOST::int8_t etc.

// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
#if defined(HAVE_STDINT_H)
#include <stdint.h>
#define BOOST

// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
#elif defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#define BOOST

#else
struct BOOST {
#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
        typedef signed char int8_t;
        typedef unsigned char uint8_t;
#else
        // No suitable 8-bit type available
        typedef struct see_blargg_common_h int8_t;
        typedef struct see_blargg_common_h uint8_t;
#endif

#if USHRT_MAX == 0xFFFF
        typedef short int16_t;
        typedef unsigned short uint16_t;
#else
        // No suitable 16-bit type available
        typedef struct see_blargg_common_h int16_t;
        typedef struct see_blargg_common_h uint16_t;
#endif

#if ULONG_MAX == 0xFFFFFFFF
        typedef long int32_t;
        typedef unsigned long uint32_t;
#elif UINT_MAX == 0xFFFFFFFF
        typedef int int32_t;
        typedef unsigned int uint32_t;
#else
        // No suitable 32-bit type available
        typedef struct see_blargg_common_h int32_t;
        typedef struct see_blargg_common_h uint32_t;
#endif
};
#endif

#if __GNUC__ >= 3
#define BLARGG_DEPRECATED __attribute__((deprecated))
#else
#define BLARGG_DEPRECATED
#endif

// Use in place of "= 0;" for a pure virtual, since these cause calls to std C++ lib.
// During development, BLARGG_PURE( x ) expands to = 0;
// virtual int func() BLARGG_PURE( { return 0; } )
#ifndef BLARGG_PURE
#define BLARGG_PURE(def) def
#endif

#endif
#endif
