/*
  Copyright (C) 2010-2011  Charles Pence <charles@charlespence.net>
  Copyright (C) 1996-1997  Id Software, Inc.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UTIL_CAST_H__
#define UTIL_CAST_H__

//
// Increase the performance of boost::lexical_cast for integers, floats, and
// doubles (our most common few conversions)
// http://stackoverflow.com/questions/1250795/very-poor-boostlexical-cast-performance
//
namespace boost
{

template<>
inline std::string lexical_cast(const int &arg)
{
    // Works up to 64-bit integers
    char buffer[65];
    sprintf(buffer, "%i", arg);
    return std::string(buffer);
}

template<>
inline std::string lexical_cast(const unsigned int &arg)
{
    // Works up to 64-bit integers
    char buffer[65];
    sprintf(buffer, "%u", arg);
    return std::string(buffer);
}

template<>
inline std::string lexical_cast(const double &arg)
{
    // This is the buffer size that Microsoft uses internally for
    // the fcvt() function, so it should be big enough
    char buffer[349];
    sprintf(buffer, "%f", arg);
    return std::string(buffer);
}

template<>
inline std::string lexical_cast(const float &arg)
{
    return lexical_cast<std::string, double>((double)arg);
}

template<>
inline int lexical_cast(const std::string &arg)
{
    char *stop;
    int ret = (int)strtol(arg.c_str(), &stop, 10);
    if (*stop != 0)
        throw_exception(bad_lexical_cast(typeid(int), typeid(std::string)));
    return ret;
}

template<>
inline unsigned int lexical_cast(const std::string &arg)
{
    char *stop;
    unsigned int ret = (unsigned int)strtoul(arg.c_str(), &stop, 10);
    if (*stop != 0)
        throw_exception(bad_lexical_cast(typeid(unsigned int), typeid(std::string)));
    return ret;
}

template<>
inline float lexical_cast(const std::string &arg)
{
    char *stop;
    float ret = (float)strtod(arg.c_str(), &stop);
    if (*stop != 0)
        throw_exception(bad_lexical_cast(typeid(float), typeid(std::string)));
    return ret;
}

template<>
inline double lexical_cast(const std::string &arg)
{
    char *stop;
    double ret = strtod(arg.c_str(), &stop);
    if (*stop != 0)
        throw_exception(bad_lexical_cast(typeid(double), typeid(std::string)));
    return ret;
}

}

namespace Util
{

template<typename Target, typename Source>
Target lexical_cast(const Source &arg)
{
    try
    {
        Target targ(boost::lexical_cast<Target>(arg));
        return targ;
    }
    catch(boost::bad_lexical_cast &)
    {
        return Target();
    }
}

}

#endif /* UTIL_CAST_H__ */
