/**
 * vec - a tiny SIMD vector library in C99
 * 
 * Copyright (c) 2024-2025 Paper
 * 
 * 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.
**/

#ifndef VEC_DEFS_H_
#define VEC_DEFS_H_

#include <string.h>
#include <stdlib.h>
#include <math.h> /* fmod */

#ifdef __has_include
# define VEC_HAS_INCLUDE(x) __has_include(x)
#else
# define VEC_HAS_INCLUDE(x)
#endif

#ifdef VEC_CUSTOM_INTEGER_TYPEDEF
/* we already have custom integer typedefs; */
# include "impl/integer.h"
#else
# if defined(__cplusplus) && VEC_HAS_INCLUDE(<cstdint>) && VEC_HAS_INCLUDE(<cstddef>)
#  include <cstdint>
#  include <cstddef>
typedef std::size_t    vec_uintsize;

typedef std::uint8_t   vec_uint8;
typedef std::uint16_t  vec_uint16;
typedef std::uint32_t  vec_uint32;
typedef std::uint64_t  vec_uint64;
typedef std::uintmax_t vec_uintmax;
typedef std::uintptr_t vec_uintptr;

typedef std::int8_t    vec_int8;
typedef std::int16_t   vec_int16;
typedef std::int32_t   vec_int32;
typedef std::int64_t   vec_int64;
typedef std::intmax_t  vec_intmax;
# elif (__STDC_VERSION__ >= 199901L) || (VEC_HAS_INCLUDE(<stdint.h>) && VEC_HAS_INCLUDE(<stddef.h>))
#  include <stdint.h>
#  include <stddef.h>
typedef uint8_t   vec_uint8;
typedef uint16_t  vec_uint16;
typedef uint32_t  vec_uint32;
typedef uint64_t  vec_uint64;
typedef uintmax_t vec_uintmax;
typedef uintptr_t vec_uintptr;
typedef size_t    vec_uintsize;
typedef int8_t    vec_int8;
typedef int16_t   vec_int16;
typedef int32_t   vec_int32;
typedef int64_t   vec_int64;
typedef intmax_t  vec_intmax;
# else
#  error Unable to find integer types with known size.
# endif

/* this isn't necessarily true, but who cares :) */
typedef float vec_f32;
typedef double vec_f64;

#endif

#define VEC_SEMVER_ATLEAST(a, b, c, x, y, z) \
	(((a) >= (x)) && \
	 ((a) > x || (b) >= (y)) && \
	 ((a) > x || (b) > (y) || (c) >= (z)))

#ifdef __GNUC__
# define VEC_GNUC_ATLEAST(x, y, z) \
	VEC_SEMVER_ATLEAST(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, x, y, z)
#else
# define VEC_GNUC_ATLEAST(x, y, z) (0)
#endif

/* GCC/clang attributes */
#if defined(__has_attribute)
# define VEC_GNUC_HAS_ATTRIBUTE(x, major, minor, patch) __has_attribute(x)
#else
# define VEC_GNUC_HAS_ATTRIBUTE(x, major, minor, patch) VEC_GNUC_ATLEAST(major, minor, patch)
#endif

#if (__cplusplus >= 201103L) || (__STDC_VERSION__ >= 202311L)
# define VEC_STATIC_ASSERT(x, msg) static_assert(x, msg)
#elif (__STDC_VERSION__ >= 201112L)
# define VEC_STATIC_ASSERT(x, msg) _Static_assert(x, msg)
#else
# define VEC_STATIC_ASSERT(x, msg) \
	extern int (*vec_impl_Static_assert_function_(void)) \
		[!!sizeof (struct { int __error_if_negative: (x) ? 2 : -1; })]
#endif

#if VEC_GNUC_HAS_ATTRIBUTE(__always_inline__, 4, 0, 0)
# define VEC_ALWAYS_INLINE __attribute__((__always_inline__))
#else
# define VEC_ALWAYS_INLINE
#endif

#define VEC_FUNC_IMPL static inline VEC_ALWAYS_INLINE

/* --------------------------------------------------------------- */
/* Get maximum value for type */

#define VEC_TYPE_SIGNED(t) (((t)(-1)) < ((t)0))

#define VEC_MAX_EX(t, TOPBIT) \
	(((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | \
      ((TOPBIT) << ((sizeof(t) * 8ULL) - 4ULL)))

#define VEC_MAX_OF_UNSIGNED(t) VEC_MAX_EX(t, 0xFULL)
#define VEC_MAX_OF_SIGNED(t) VEC_MAX_EX(t, 0x7ULL)

#define VEC_MAX_OF_TYPE(t) \
	((unsigned long long)(VEC_TYPE_SIGNED(t) \
		? VEC_MAX_OF_SIGNED(t) \
		: VEC_MAX_OF_UNSIGNED(t)))

#endif /* VEC_DEFS_H */
