// Do not edit binpac.h, edit binpac.h.in instead!

#ifndef binpac_h
#define binpac_h

#ifndef _MSC_VER
#include <sys/param.h>
#endif

/* #undef HOST_BIGENDIAN */
#ifdef HOST_BIGENDIAN
#define HOST_BYTEORDER bigendian
#else
#define HOST_BYTEORDER littleendian
#endif

#include <cassert>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <string>

// Expose C99 functionality from inttypes.h, which would otherwise not be
// available in C++.
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

static constexpr void BINPAC_ASSERT(bool val) { assert(val); }

using namespace std;

namespace binpac {

const int bigendian = 0;
const int littleendian = 1;
const int unspecified_byteorder = -1;

#ifndef pac_type_defs
#define pac_type_defs

using int8 = int8_t;
using int16 = int16_t;
using int32 = int32_t;
using int64 = int64_t;
using uint8 = uint8_t;
using uint16 = uint16_t;
using uint32 = uint32_t;
using uint64 = uint64_t;
using nulptr = void*;
using voidptr = void*;
using byteptr = uint8*;
using const_byteptr = const uint8*;
using const_charptr = const char*;

static_assert(sizeof(unsigned int) == 4, "Unexpected size of unsigned int");

#endif /* pac_type_defs */

/* Handling byte order */

namespace {

inline uint16 pac_swap(const uint16 x) { return (x >> 8) | ((x & 0xff) << 8); }

inline int16 pac_swap(const int16 x) {
    // Forward to unsigned version with argument/result casted
    // appropriately.
    uint16 (*p)(const uint16) = &pac_swap;
    return (*p)(x);
}

inline uint32 pac_swap(const uint32 x) {
    return (x >> 24) | ((x & 0xff0000) >> 8) | ((x & 0xff00) << 8) | ((x & 0xff) << 24);
}

inline int32 pac_swap(const int32 x) {
    // Forward to unsigned version with argument/result casted
    // appropriately.
    uint32 (*p)(const uint32) = &pac_swap;
    return (*p)(x);
}

inline uint64 pac_swap(const uint64 x) {
    return x >> 56 | (x & 0xff000000000000) >> 40 | (x & 0xff0000000000) >> 24 | (x & 0xff00000000) >> 8 |
           (x & 0xff000000) << 8 | (x & 0xff0000) << 24 | (x & 0xff00) << 40 | (x & 0xff) << 56;
}

inline int64 pac_swap(const int64 x) {
    // Forward to unsigned version with argument/result casted
    // appropriately.
    uint64 (*p)(const uint64) = &pac_swap;
    return (*p)(x);
}

template<typename T>
static constexpr T FixByteOrder(int byteorder, T x) {
    if ( byteorder == HOST_BYTEORDER )
        return x;

    return static_cast<T>(pac_swap(x));
}

template<class T>
inline T UnMarshall(const unsigned char* data, int byteorder) {
    T result = 0;
    for ( int i = 0; i < (int)sizeof(T); ++i )
        result = (result << 8) | data[byteorder == bigendian ? i : sizeof(T) - 1 - i];
    return result;
}

inline const char* do_fmt(const char* format, va_list ap) {
    static char buf[1024];
    vsnprintf(buf, sizeof(buf), format, ap);
    return buf;
}

inline string strfmt(const char* format, ...) {
    va_list ap;
    va_start(ap, format);
    const char* r = do_fmt(format, ap);
    va_end(ap);
    return {r};
}

} // anonymous namespace

// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define binpac_fmt(...) strfmt(__VA_ARGS__).c_str()

class RefCount {
public:
    RefCount() { count = 1; }
    virtual ~RefCount() = default;
    void Ref() { ++count; }
    int Unref() {
        BINPAC_ASSERT(count > 0);
        return --count;
    }

private:
    int count;
};

namespace {
inline void Unref(RefCount* x) {
    if ( x && x->Unref() <= 0 )
        delete x;
}
} // anonymous namespace

} // namespace binpac

#include "binpac_analyzer.h"
#include "binpac_buffer.h"
#include "binpac_bytestring.h"
#include "binpac_exception.h"
#include "binpac_regex.h"

#endif /* binpac_h */
