/**
 * \file
 *
 * \brief Misc utility functions and definitions
 *
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
 * - Supported devices:  All devices
 * - AppNote:
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support and FAQ: http://support.atmel.no/
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 * Atmel AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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 UTIL_H_INCLUDED
#define UTIL_H_INCLUDED

#include <types.h>

/**
 * \brief Stringify the result after expansion of a macro argument.
 */
#define xstr(s)		str(s)

/**
 * \brief Stringify a macro argument without expansion.
 */
#define str(s)		#s

/**
 * \brief Get the number of elements in array @a a.
 */
#define ARRAY_LEN(a)	(sizeof(a) / sizeof((a)[0]))

/**
 * \brief Determine whether or not the character @a c is a digit.
 *
 * \param c The character to consider.
 * \retval 0 The character \a c is not a digit.
 * \retval 1 The character \a c is a digit.
 */
static inline int isdigit(int c)
{
	return (c >= '0') && (c <= '9');
}

/**
 * \brief Determine whether or not the character \a c is a control
 * character.
 *
 * \param c The character to consider.
 * \retval 0 The character \a c is not a control character.
 * \retval 1 The character \a c is a control character.
 */
static inline int iscntrl(int c)
{
	return (c < 32) || (c >= 127);
}

/**
 * \brief Determine whether or not the character \a c is a space.
 *
 * \note This implementation is very limited in that it doesn't
 * consider a bunch of control characters that probably should be
 * interpreted as space.
 *
 * \param c The character to consider.
 * \retval 0 The character \a c is not a space.
 * \retval 1 The character \a c is a space.
 */
static inline int isspace(int c)
{
	return c == ' ';
}

/**
 * \brief Get the containing object.
 *
 * \param ptr Pointer to the contained object.
 * \param type Type of the containing object.
 * \param member Member name of the contained object inside the
 *	containing object.
 * \return Pointer to the containing object.
 */
#define container_of(ptr, type, member)					\
	((type *)((unsigned long)(ptr) - offsetof(type, member)))

/**
 * \internal
 * Undefined function. Will cause a link failure if ilog2() is called
 * with an invalid constant value.
 */
int ilog2_undefined(void);

/**
 * \brief Calculate the base-2 logarithm of a number rounded down to
 * the nearest integer.
 *
 * \param x A 32-bit value
 * \return The base-2 logarithm of \a x, or -1 if \a x is 0.
 */
static inline int ilog2(unsigned int x)
{
	if (is_constant(x))
		return ((x) & (1ULL << 31) ? 31 :
			(x) & (1ULL << 30) ? 30 :
			(x) & (1ULL << 29) ? 29 :
			(x) & (1ULL << 28) ? 28 :
			(x) & (1ULL << 27) ? 27 :
			(x) & (1ULL << 26) ? 26 :
			(x) & (1ULL << 25) ? 25 :
			(x) & (1ULL << 24) ? 24 :
			(x) & (1ULL << 23) ? 23 :
			(x) & (1ULL << 22) ? 22 :
			(x) & (1ULL << 21) ? 21 :
			(x) & (1ULL << 20) ? 20 :
			(x) & (1ULL << 19) ? 19 :
			(x) & (1ULL << 18) ? 18 :
			(x) & (1ULL << 17) ? 17 :
			(x) & (1ULL << 16) ? 16 :
			(x) & (1ULL << 15) ? 15 :
			(x) & (1ULL << 14) ? 14 :
			(x) & (1ULL << 13) ? 13 :
			(x) & (1ULL << 12) ? 12 :
			(x) & (1ULL << 11) ? 11 :
			(x) & (1ULL << 10) ? 10 :
			(x) & (1ULL <<  9) ?  9 :
			(x) & (1ULL <<  8) ?  8 :
			(x) & (1ULL <<  7) ?  7 :
			(x) & (1ULL <<  6) ?  6 :
			(x) & (1ULL <<  5) ?  5 :
			(x) & (1ULL <<  4) ?  4 :
			(x) & (1ULL <<  3) ?  3 :
			(x) & (1ULL <<  2) ?  2 :
			(x) & (1ULL <<  1) ?  1 :
			(x) & (1ULL <<  0) ?  0 :
			ilog2_undefined());

	return 31 - count_leading_zeroes(x);
}

/**
 * \brief Test if a given value is a power of two.
 *
 * \param x The value to test
 * \return true if \a x is a power of two, false otherwise
 */
static inline bool is_power_of_two(unsigned long x)
{
	return x && !(x & (x - 1));
}

/**
 * \brief Round down to the nearest power of two boundary.
 *
 * \param x A positive integer
 * \param order log2 of the required boundary.
 * \return \a x rounded down to the nearest multiple of (1 << \a order)
 */
static inline unsigned long round_down(unsigned long x, unsigned int order)
{
	return x & ~((1UL << order) - 1);
}

/**
 * \brief Round up to the nearest power of two boundary.
 *
 * \param x A positive integer
 * \param order log2 of the required boundary.
 * \return \a x rounded up to the next multiple of (1 << \a order)
 */
static inline unsigned long round_up(unsigned long x, unsigned int order)
{
	return round_down(x + (1UL << order) - 1, order);
}

/**
 * \brief Round up to the nearest word-aligned boundary.
 *
 * \param x Address or offset to be word-aligned
 * \return The smallest number \a y where \a y >= \a x and \a y & 3 == 0.
 */
static inline unsigned long word_align(unsigned long x)
{
	return round_up(x, 2);
}

#ifdef CONFIG_PAGE_SIZE
/**
 * Round up to the nearest multiple of #CONFIG_PAGE_SIZE.
 *
 * \param x Address or offset to be page aligned
 * \return The smallest number \a y where \a y >= @a x and
 * \a y % #CONFIG_PAGE_SIZE == 0.
 */
static inline unsigned long page_align(unsigned long x)
{
	return (x + CONFIG_PAGE_SIZE - 1) & ~(CONFIG_PAGE_SIZE - 1);
}
#endif

/**
 * \brief Calculate \f$ \left\lceil \frac{a}{b} \right\rceil \f$ using
 * integer arithmetic.
 *
 * \param a An integer
 * \param b Another integer
 *
 * \return (\a a / \a b) rounded up to the nearest integer.
 */
#define div_ceil(a, b)	(((a) + (b) - 1) / (b))

#endif /* UTIL_H_INCLUDED */
