/*
# This file is part of the Astrometry.net suite.
# Licensed under a 3-clause BSD style license - see LICENSE
*/
#ifndef OS_FEATURES_H
#define OS_FEATURES_H

// This is actually in POSIX1b but may or may not be available.
int fdatasync(int fd);

// Not POSIX; doesn't exist in Solaris 10
//#include <sys/param.h>
#ifndef MIN
#define	MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define	MAX(a,b) (((a)>(b))?(a):(b))
#endif

// isfinite() on Solaris; from
// https://code.google.com/p/redis/issues/detail?id=20
#if defined(__sun) && defined(__GNUC__)

#undef isnan
#define isnan(x) \
      __extension__({ __typeof (x) __x_a = (x); \
      __builtin_expect(__x_a != __x_a, 0); })

#undef isfinite
#define isfinite(x) \
      __extension__ ({ __typeof (x) __x_f = (x); \
      __builtin_expect(!isnan(__x_f - __x_f), 1); })

#undef isinf
#define isinf(x) \
      __extension__ ({ __typeof (x) __x_i = (x); \
      __builtin_expect(!isnan(__x_i) && !isfinite(__x_i), 0); })

#undef isnormal
#define isnormal(x) \
  __extension__ ({ __typeof(x) __x_n = (x); \
                   if (__x_n < 0.0) __x_n = -__x_n; \
                   __builtin_expect(isfinite(__x_n) \
                                    && (sizeof(__x_n) == sizeof(float) \
                                          ? __x_n >= __FLT_MIN__ \
                                          : sizeof(__x_n) == sizeof(long double) \
                                            ? __x_n >= __LDBL_MIN__ \
                                            : __x_n >= __DBL_MIN__), 1); })

#undef HUGE_VALF
#define HUGE_VALF (1e50f)

#endif

/**
   The qsort_r story:

   -qsort_r appears in BSD (including Mac OSX)
         void qsort_r(void *, size_t, size_t,
                      void *,
                      int (*)(void *, const void *, const void *));

   -qsort_r appears in glibc 2.8, but with a different argument order:
         void qsort_r(void*, size_t, size_t,
                      int (*)(const void*, const void*, void*),
                      void*);

   Notice that the "thunk" and "comparison function" arguments to qsort_r are
   swapped, and the "thunk" appears either at the beginning or end of the comparison
   function.

   We check a few things:
   -is qsort_r declared?
   -does qsort_r exist?
   -do we need to swap the arguments?

   Those using qsort_r in Astrometry.net should instead use the macro QSORT_R()
   to take advantage of these tests.

   Its signature is:

   void QSORT_R(void* base, size_t nmembers, size_t member_size,
                void* token, comparison_function);

   You should define the "comparison" function like this:

   static int QSORT_COMPARISON_FUNCTION(my_comparison, void* token, const void* v1, const void* v2) {
     ...
   }


   Distributions including glibc 2.8 include:
   -Mandriva 2009
   -Ubuntu 8.10
*/

///// In this healpix distribution, we avoid all this mess by importing
///// a stand-alone qsort_reentrant implementation.

typedef int             cmp_t(void *, const void *, const void *);
void
qsort_rex(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp);

#define QSORT_R qsort_rex
#define QSORT_COMPARISON_FUNCTION(func, thunk, v1, v2) func(thunk, v1, v2)

// As suggested in http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Names.html
#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
#  define __func__ __FUNCTION__
# else
#  define __func__ "<unknown>"
# endif
#endif

#endif
