// ---------------------------------------------------------------------------------------------------------------------------------
//        _   _ _
//       | | (_) |
//  _   _| |_ _| |
// | | | | __| | |
// | |_| | |_| | |
//  \__,_|\__|_|_|
//
//
//
// Description:
//
//   Miscellaneous utilitarian functions
//
// Notes:
//
//   Best viewed with 8-character tabs and (at least) 132 columns
//
// History:
//
//   04/13/2001 by Paul Nettle: Original creation
//
// Restrictions & freedoms pertaining to usage and redistribution of this software:
//
//   This software is 100% free. If you use this software (in part or in whole) you must credit the author. This software may not be
//   re-distributed (in part or in whole) in a modified form without clear documentation on how to obtain a copy of the original
//   work. You may not use this software to directly or indirectly cause harm to others. This software is provided as-is and without
//   warrantee -- Use at your own risk. For more information, visit HTTP://www.FluidStudios.com/
//
// Copyright 2001, Fluid Studios, Inc., all rights reserved.
// ---------------------------------------------------------------------------------------------------------------------------------

#ifndef	_FSTL_UTIL
#define _FSTL_UTIL

// ---------------------------------------------------------------------------------------------------------------------------------
// Module setup (required includes, macros, etc.)
// ---------------------------------------------------------------------------------------------------------------------------------

#include <new>
#include "common"

FSTL_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T	pi()
{
	return (T) 3.14159265359;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T	toRadians(const T & a)
{
	return pi<T>() / (T) 180.0 * a;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T	toDegrees(const T & a)
{
	return (T) 180.0 / pi<T>() * a;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T &	min(const T & a, const T & b)
{
	return (a < b) ? a : b;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T &	max(const T & a, const T & b)
{
	return (a > b) ? a : b;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T	abs(const T & a)
{
	return (a < 0) ? -a : a;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	swap(T& a, T& b)
{
	T c(a);
	a = b;
	b = c;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T *	allocate(const unsigned int count)
{
	T *	ptr = static_cast<T *>(operator new(sizeof(T) * count));
	if (!ptr) throwstring("", "Out of memory");
	return	ptr;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	deallocate(T* ptr)
{
	operator delete(ptr);
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T *	construct(T* ptr)
{
	return new (static_cast<void *>(ptr)) T;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T, class Tz>
inline	T *	construct(T* ptr, Tz &src)
{
	return new (static_cast<void *>(ptr)) T(src);
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	destruct(T* ptr)
{
	if (ptr) ptr->~T();
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	destructElements(T* ptr, const unsigned int count)
{
	for (unsigned int i = 0; i < count; ++i)
	{
		destruct(&ptr[i]);
	}
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	moveElements(T* dst, T* src, const unsigned int count)
{
	// Supposed to be doing anything?

	if (!count) return;

	// Copying forward or backwards?
	
	if (dst < src)
	{
		for (unsigned int i = 0; i < count; ++i, ++dst, ++src)
		{
			*dst = *src;
		}
	}
	else
	{
		T*	s = src + count - 1;
		T*	d = dst + count - 1;
		for (unsigned int i = 0; i < count; ++i, --d, --s)
		{
			*d = *s;
		}
	}
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	copyElements(T* dst, T* src, const unsigned int count)
{
	// Supposed to be doing anything?

	if (!count) return;

	for (unsigned int i = 0; i < count; ++i, ++dst, ++src)
	{
		construct(dst, *src);
	}
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	fillElements(T* dst, const T& src, const unsigned int count)
{
	for (unsigned int i = 0; i < count; ++i, ++dst)
	{
		*dst = src;
	}
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	invertElements(T* ptr, const unsigned int count)
{
	T *	p0 = ptr;
	T *	p1 = ptr + count - 1;

	while(p0 < p1)
	{
		swap(*p0, *p1);
		++p0;
		--p1;
	}
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T	toupper(T& c)
{
	return (c >= static_cast<T>('a') && c <= static_cast<T>('z')) ? (c - static_cast<T>('a'-'A')):c;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	T	tolower(T& c)
{
	return (c >= static_cast<T>('A') && c <= static_cast<T>('Z')) ? (c + static_cast<T>('a'-'A')):c;
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	bool	isspace(T c)
{
	return	(c == static_cast<T>(' ' )) ||
		(c == static_cast<T>('\t')) ||
		(c == static_cast<T>('\v')) ||
		(c == static_cast<T>('\r')) ||
		(c == static_cast<T>('\n')) ||
		(c == static_cast<T>('\f'));
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	bool	isdigit(T c)
{
	return (c >= static_cast<T>('0')) && (c <= static_cast<T>('9'));
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	bool	isalpha(T c)
{
	return	(c >= static_cast<T>('a') && c <= static_cast<T>('z')) ||
		(c >= static_cast<T>('A') && c <= static_cast<T>('Z'));
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	bool	isalnum(T c)
{
	return isalpha(c) || isdigit(c);
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	zeromem(T* dst, unsigned int count = 1)
{
	::memset(dst, 0, sizeof(T) * count);
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	memset(T* dst, T fill, unsigned int count)
{
	if (sizeof(T) == 1)
	{
		::memset(dst, fill, count);
	}
	else
	{
		while(count--) *(dst++) = fill;
	}
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	memcpy(T* dst, const T* src, unsigned int count)
{
	::memcpy(dst, src, sizeof(T) * count);
}

// ---------------------------------------------------------------------------------------------------------------------------------

template <class T>
inline	void	memmove(T* dst, const T* src, unsigned int count)
{
	::memmove(dst, src, sizeof(T) * count);
}

FSTL_NAMESPACE_END
#endif // _FSTL_UTIL
// ---------------------------------------------------------------------------------------------------------------------------------
// util - End of file
// ---------------------------------------------------------------------------------------------------------------------------------

