/*
 * ccompat.h
 *
 *  Created on: 1/06/2017.
 *      Author: alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
 */

#ifndef LWB_CORE_CCOMPAT_H_
#define LWB_CORE_CCOMPAT_H_


#include <compiler-port.h>

#ifndef INLINE
#   ifdef __cplusplus
#       define INLINE inline
#   else
//  если не делать static - то объектники начнут кофликтовать своими многочисленными
//  копиями инлайнов при сборке. сделать инлайн слабым (weak)
#       define INLINE static inline
#   endif
#endif

/** from linux stdlib */

#ifndef __nonnull
#define __nonnull(seq) __attribute__((nonull seq ))
#endif

#ifndef __CONST
#define __CONST __attribute__ ((__const__))
#endif

#define __PURE      __attribute__ ((__pure__))
#define __NORETURN  __attribute__ ((__noreturn__))

/* Convenience macros to test the versions of glibc and gcc.
   Use them like this:
   #if __GNUC_PREREQ (2,8)
   ... code requiring gcc 2.8 or later ...
   #endif
   Note - they won't work for gcc1 or glibc1, since the _MINOR macros
   were not defined then.  */
#ifndef __GNUC_PREREQ
#if defined __GNUC__ && defined __GNUC_MINOR__
# define __GNUC_PREREQ(maj, min) \
    ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
# define __GNUC_PREREQ(maj, min) 0
#endif
#endif

#ifndef __USED
/* At some point during the gcc 3.1 development the `used' attribute
   for functions was introduced.  We don't want to use it unconditionally
   (although this would be possible) since it generates warnings.  */
#if __GNUC_PREREQ (3,1)
# define __USED __attribute__ ((__used__))
#else
# define __USED
#endif
#endif //__USED

#ifndef __UNUSED
/* At some point during the gcc 3.1 development the `unused' attribute
   for functions was introduced.  We don't want to use it unconditionally
   (although this would be possible) since it generates warnings.  */
#if __GNUC_PREREQ (3,1)
# define __UNUSED __attribute__ ((__unused__))
#else
# define __UNUSED
#endif
#endif //__USED

/* At some point during the gcc 3.1 development the `used' attribute
   for functions was introduced.  We don't want to use it unconditionally
   (although this would be possible) since it generates warnings.  */
#ifndef __NOINLINE
#if __GNUC_PREREQ (3,1)
# define __NOINLINE __attribute__ ((__noinline__))
#else
# define __NOINLINE /* Ignore */
#endif
#endif

#ifndef __deprecated
/* gcc allows marking deprecated functions.  */
#if __GNUC_PREREQ (3,2)
# define __deprecated __attribute__ ((__deprecated__))
#else
# define __deprecated /* Ignore */
#endif
#endif

#ifndef __weak_symbol
# define __weak_symbol __attribute__((weak))
#endif

#ifndef __WEAK
# define __WEAK     __weak_symbol
#endif

// keil and iar compilers have __week
#ifdef __GNUC__
#define __week      __weak_symbol
#endif

#ifndef __WEAK_REF
#ifdef __GNUC__
#define __WEAK_REF( default_ref )    __attribute__((weak, alias(default_ref)))
#endif
#endif

#ifndef __always_inline
# define __always_inline        __attribute__((always_inline))
#endif

# define __must_check           __attribute__((warn_unused_result))

#if __GNUC__ >= 3
# define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
# define __glibc_likely(cond)   __builtin_expect ((cond), 1)
#else
# define __glibc_unlikely(cond) (cond)
# define __glibc_likely(cond)   (cond)
#endif

#ifndef LIKELY

#ifdef __GNUC__
#define LIKELY(cond)    __glibc_likely(cond)
#define UNLIKELY(cond)  __glibc_unlikely(cond)
#else
#define LIKELY(cond)    cond
#define UNLIKELY(cond)  cond
#endif

#endif //LIKELY

//* __NOTHROW declares that routine not rises exception, in c++11 same as noexcept
#ifndef __NOTHROW
#if __cplusplus

#if defined ( __CC_ARM )
#  define __NOTHROW     __declspec(nothrow)
#  define NOT_THROWS( decl ) __declspec(nothrow) decl
#elif defined( __GNUC__ )
#  define __NOTHROW     __attribute__((nothrow))
#  define NOT_THROWS( decl ) decl __attribute__((nothrow))
#else
#  define __NOTHROW     __attribute__((nothrow))
#  define NOT_THROWS( decl ) decl __attribute__((nothrow))
#endif

#else
#  define __NOTHROW
#  define NOT_THROWS( decl ) decl
#endif//__cplusplus
#endif//ifndef __NOTHROW

#if __cplusplus >= 201103L
//since GCC 4.7 supports C++11 noexcept keyword use it with stantart gcc nothrow attribute
#  define __noexcept    noexcept
#else
#  if __cplusplus
#  define __noexcept    throw()
#  else
#  define __noexcept
#  endif
#endif

/* gcc's handling of attribute nonnull is less than stellar - it does
* NOT improve diagnostics, and merely allows gcc to optimize away
* null code checks even when the caller manages to pass null in spite
* of the attribute, leading to weird crashes. Coverity, on the other
* hand, knows how to do better static analysis based on knowing
* whether a parameter is nonnull. Make this attribute conditional
* based on whether we are compiling for real or for analysis, while
* still requiring correct gcc syntax when it is turned off. See also
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17308 */
# ifndef __NONNULL
# if __GNUC_PREREQ (3, 3)
# if STATIC_ANALYSIS
# define __NONNULL(m) __attribute__((__nonnull__(m)))
# else
# define __NONNULL(m) __attribute__(())
# endif
# else
# define ATTRIBUTE_NONNULL(m)
# endif
# endif

# if __cplusplus >= 201103L
// GNU disables typeof in C++11, must use decltype
#define typeof(x)   decltype(x)
#endif

#define OFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define ARRAY_COUNT(x)    (sizeof(x)/sizeof((x)[0]))



//* look the trick https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s
#define __VA_NARG__(...) \
        (__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1)
#define __VA_NARG_(...) \
        __VA_ARG_N(__VA_ARGS__)
#define __VA_ARG_N( \
         _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
        _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
        _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
        _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
        _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
        _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
        _61,_62,_63\
        ,N,...) N
#define __RSEQ_N() \
        63, 62, 61, 60,                         \
        59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
        49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
        39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
        29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
        19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
         9,  8,  7,  6,  5,  4,  3,  2,  1,  0


#define __VA_CONCAT_IMPL(x, y) x##y
#define __VA_CONCAT(x, y) __VA_CONCAT_IMPL( x, y )
#define __VA_OVERRIDE__(macro, ...) __VA_CONCAT(macro, __VA_NARG__(__VA_ARGS__))



//*****************************************************************

// @brief is exact power2 number - only 1bit
#define IS_POW2(x) ( (((x)-1) & (x))== 0 )

#define LOG2_1(n) (((n) >= 2) ? 1 : 0)
#define LOG2_2(n) (((n) >= 1<<2) ? (2 + LOG2_1((n)>>2)) : LOG2_1(n))
#define LOG2_4(n) (((n) >= 1<<4) ? (4 + LOG2_2((n)>>4)) : LOG2_2(n))
#define LOG2_8(n) (((n) >= 1<<8) ? (8 + LOG2_4((n)>>8)) : LOG2_4(n))
#define LOG2(n)   (((n) >= 1<<16) ? (16 + LOG2_8((n)>>16)) : LOG2_8(n))

// @brief is low n-bits clear
#define IS_CTZn(x, n)   ( ((x) & ((1<<(n))-1)) == 0 )

#define CTZ_1(n) ( IS_CTZn((n), 1) ? 1 : 0)
#define CTZ_2(n) ( IS_CTZn((n), 2) ? (2 + CTZ_1((n)>>2)) : CTZ_1(n))
#define CTZ_4(n) ( IS_CTZn((n), 4) ? (4 + CTZ_2((n)>>4)) : CTZ_2(n))
#define CTZ_8(n) ( IS_CTZn((n), 8) ? (8 + CTZ_4((n)>>8)) : CTZ_4(n))
#define CTZ(n)   ( IS_CTZn((n), 16) ? (16 + CTZ_8((n)>>16)) : CTZ_8(n) )


// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
#define SH1(v)  ((v-1) | ((v-1) >> 1))            // accidently came up w/ this...
#define SH2(v)  ((v) | ((v) >> 2))
#define SH4(v)  ((v) | ((v) >> 4))
#define SH8(v)  ((v) | ((v) >> 8))
#define SH16(v) ((v) | ((v) >> 16))
#define POW2_CEIL(v) (SH16(SH8(SH4(SH2(SH1(v))))) + 1)

//*****************************************************************
#define __c_decl    __noexcept __NOTHROW
#define __cpp_decls __c_decl

#if defined(__MSP430_CPU__) || (__MSP430__)
#define PROGMEM
#elif defined(__AVR__)
#include <avr/pgmspace.h>
#else
#define PROGMEM
#endif



#endif /* LWB_CORE_CCOMPAT_H_ */
