#define new(type) new type
#define proc auto

#ifdef _DEBUG
constexpr bool is_debug_build = true;
#else
constexpr bool is_debug_build = false;
#endif

#define if_debug if constexpr (is_debug_build)

#ifdef _MSC_VER
# define if_windows if constexpr (1)
# define if_linux   if constexpr (0)
# define debug_break() if_debug __debugbreak()
#else
# include <signal.h>
# define debug_break() if_debug raise(SIGTRAP)
# define if_windows if (0)
# define if_linux   if (1)
#endif

#define assert(cond)                                                    \
    if_debug {                                                          \
        if (!cond) {                                                    \
            if (log_level == Log_Level::Debug) {                        \
                printf("Assertion failed: %s %d", __FILE__, __LINE__);  \
            }                                                           \
            debug_break();                                              \
        }                                                               \
    } else {}                                                           \

#define concat_( a, b) a##b
#define label(prefix, lnum) concat_(prefix,lnum)
#define try                                                             \
    if (1)                                                              \
        goto label(body,__LINE__);                                      \
    else                                                                \
        while (1)                                                       \
            if (1) {                                                    \
                if(error) {                                             \
                    if (log_level == Log_Level::Debug) {                \
                        printf("in %s:%d\n", __FILE__, __LINE__);       \
                    }                                                   \
                    return 0;                                           \
                }                                                       \
                break;                                                  \
            }                                                           \
            else label(body,__LINE__):

#define try_void                                                        \
    if (1)                                                              \
        goto label(body,__LINE__);                                      \
    else                                                                \
        while (1)                                                       \
            if (1) {                                                    \
                if(error) {                                             \
                    if (log_level == Log_Level::Debug) {                \
                        printf("in %s:%d\n", __FILE__, __LINE__);       \
                    }                                                   \
                    return;                                             \
                }                                                       \
                break;                                                  \
            }                                                           \
            else label(body,__LINE__):


#define define_array_list(type, name)                                   \
    struct name##_Array_List {                                          \
        type* data;                                                     \
        int length;                                                     \
        int next_index;                                                 \
    };                                                                  \
                                                                        \
                                                                        \
    proc append_to_array_list(name##_Array_List* arraylist, type element) -> void { \
        if (arraylist->next_index == arraylist->length) {               \
            arraylist->length *= 2;                                     \
            arraylist->data =                                           \
                (type*)realloc(arraylist->data, arraylist->length * sizeof(type)); \
        }                                                               \
        arraylist->data[arraylist->next_index++] = element;             \
    }                                                                   \
                                                                        \
                                                                        \
    proc create_##name##_array_list(int initial_capacity = 16) -> name##_Array_List* { \
        name##_Array_List* ret = new(name##_Array_List);                \
        ret->data = (type*)malloc(initial_capacity * sizeof(type));     \
        ret->next_index = 0;                                            \
        ret->length = initial_capacity;                                 \
        return ret;                                                     \
    }


template<typename F>
class defer_finalizer {
    F f;
    bool moved;
public:
    template<typename T>
    defer_finalizer(T && f_) : f(std::forward<T>(f_)), moved(false) { }

    defer_finalizer(const defer_finalizer &) = delete;

    defer_finalizer(defer_finalizer && other) : f(std::move(other.f)), moved(other.moved) {
        other.moved = true;
    }

    ~defer_finalizer() {
        if (!moved) f();
    }
};

struct {
    template<typename F>
    defer_finalizer<F> operator<<(F && f) {
        return defer_finalizer<F>(std::forward<F>(f));
    }
} deferrer;

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define defer auto TOKENPASTE2(__deferred_lambda_call, __COUNTER__) = deferrer << [&]

#define console_normal "\x1B[0m"
#define console_red    "\x1B[31m"
#define console_green  "\x1B[32m"
#define console_cyan   "\x1B[36m"
// #define console_normal ""
// #define console_red    ""
// #define console_green  ""
// #define console_cyan   ""
